blob: afce1949721115aec4e3f623c0ce4fac1e2fc9b7 [file] [log] [blame]
Ben Murdochc5610432016-08-08 18:44:38 +01001<html>
2<!--
3Copyright 2016 the V8 project authors. All rights reserved. Use of this source
4code is governed by a BSD-style license that can be found in the LICENSE file.
5-->
6
7<head>
8 <meta charset="UTF-8">
9 <style>
10 body {
11 font-family: arial;
12 }
13
14 table {
15 display: table;
16 border-spacing: 0px;
17 }
18
19 tr {
20 border-spacing: 0px;
21 padding: 10px;
22 }
23
24 td,
25 th {
26 padding: 3px 10px 3px 5px;
27 }
28
29 .inline {
30 display: inline-block;
31 vertical-align: top;
32 }
33
34 h2,
35 h3 {
36 margin-bottom: 0px;
37 }
38
39 .hidden {
40 display: none;
41 }
42
43 .view {
44 display: table;
45 }
46
47 .column {
48 display: table-cell;
49 border-right: 1px black dotted;
50 min-width: 200px;
51 }
52
53 .column .header {
54 padding: 0 10px 0 10px
55 }
56
57 #column {
58 display: none;
59 }
Ben Murdoch61f157c2016-09-16 13:49:30 +010060
Ben Murdochc5610432016-08-08 18:44:38 +010061 .list {
62 width: 100%;
63 }
64
65 select {
66 width: 100%
67 }
68
69 .list tbody {
70 cursor: pointer;
71 }
72
73 .list tr:nth-child(even) {
74 background-color: #EFEFEF;
75 }
76
77 .list tr:nth-child(even).selected {
78 background-color: #DDD;
79 }
80
81 .list tr.child {
82 display: none;
83 }
84
85 .list tr.child.visible {
86 display: table-row;
87 }
88
89 .list .child .name {
90 padding-left: 20px;
91 }
92
93 .list .parent td {
94 border-top: 1px solid #AAA;
95 }
96
97 .list .total {
98 font-weight: bold
99 }
100
101 .list tr.parent {
102 background-color: #FFF;
103 }
104
105 .list tr.parent.selected {
106 background-color: #DDD;
107 }
108
109 tr.selected {
110 background-color: #DDD;
111 }
112
Ben Murdoch61f157c2016-09-16 13:49:30 +0100113 .codeSearch {
114 display: block-inline;
115 float: right;
116 border-radius: 5px;
117 background-color: #EEE;
118 width: 1em;
119 text-align: center;
120 }
121
Ben Murdochc5610432016-08-08 18:44:38 +0100122 .list .position {
123 text-align: right;
124 display: none;
125 }
126
127 .list div.toggle {
128 cursor: pointer;
129 }
130
131 #column_0 .position {
132 display: table-cell;
133 }
134
135 #column_0 .name {
136 display: table-cell;
137 }
138
139 .list .name {
140 display: none;
141 white-space: nowrap;
142 }
143
144 .value {
145 text-align: right;
146 }
147
148 .selectedVersion {
149 font-weight: bold;
150 }
151
152 #baseline {
153 width: auto;
154 }
155
156 .compareSelector {
157 padding-bottom: 20px;
158 }
159
160 .pageDetailTable tbody {
161 cursor: pointer
162 }
163
164 .pageDetailTable tfoot td {
165 border-top: 1px grey solid;
166 }
167
168 #popover {
169 position: absolute;
170 transform: translateY(-50%) translateX(40px);
171 box-shadow: -2px 10px 44px -10px #000;
172 border-radius: 5px;
173 z-index: 1;
174 background-color: #FFF;
175 display: none;
176 white-space: nowrap;
177 }
178
179 #popover table {
180 position: relative;
181 z-index: 1;
182 text-align: right;
183 margin: 10px;
184 }
185 #popover td {
186 padding: 3px 0px 3px 5px;
187 white-space: nowrap;
188 }
189
190 .popoverArrow {
191 background-color: #FFF;
192 position: absolute;
193 width: 30px;
194 height: 30px;
195 transform: translateY(-50%)rotate(45deg);
196 top: 50%;
197 left: -10px;
198 z-index: 0;
199 }
200
201 #popover .name {
202 padding: 5px;
203 font-weight: bold;
204 text-align: center;
205 }
206
207 #popover table .compare {
208 display: none
209 }
210
211 #popover table.compare .compare {
212 display: table-cell;
213 }
214
215 #popover .compare .time,
216 #popover .compare .version {
217 padding-left: 10px;
218 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100219 .graph,
220 .graph .content {
221 width: 100%;
222 }
223
224 .diff .hideDiff {
225 display: none;
226 }
227 .noDiff .hideNoDiff {
228 display: none;
229 }
Ben Murdochc5610432016-08-08 18:44:38 +0100230 </style>
231 <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
232 <script type="text/javascript">
233 "use strict"
234 google.charts.load('current', {packages: ['corechart']});
235
236 // Did anybody say monkeypatching?
237 if (!NodeList.prototype.forEach) {
238 NodeList.prototype.forEach = function(func) {
239 for (var i = 0; i < this.length; i++) {
240 func(this[i]);
241 }
242 }
243 }
244
245 var versions;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100246 var pages;
Ben Murdochc5610432016-08-08 18:44:38 +0100247 var selectedPage;
248 var baselineVersion;
249 var selectedEntry;
250
251 function initialize() {
252 var original = $("column");
253 var view = document.createElement('div');
254 view.id = 'view';
255 var i = 0;
256 versions.forEach((version) => {
257 if (!version.enabled) return;
258 // add column
259 var column = original.cloneNode(true);
260 column.id = "column_" + i;
261 // Fill in all versions
262 var select = column.querySelector(".version");
263 select.id = "selectVersion_" + i;
264 // add all select options
265 versions.forEach((version) => {
266 if (!version.enabled) return;
267 var option = document.createElement("option");
268 option.textContent = version.name;
269 option.version = version;
270 select.appendChild(option);
271 });
272 // Fill in all page versions
273 select = column.querySelector(".pageVersion");
274 select.id = "select_" + i;
275 // add all pages
276 versions.forEach((version) => {
277 if (!version.enabled) return;
278 var optgroup = document.createElement("optgroup");
279 optgroup.label = version.name;
280 optgroup.version = version;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100281 version.forEachPage((page) => {
Ben Murdochc5610432016-08-08 18:44:38 +0100282 var option = document.createElement("option");
283 option.textContent = page.name;
284 option.page = page;
285 optgroup.appendChild(option);
286 });
287 select.appendChild(optgroup);
288 });
289 view.appendChild(column);
290 i++;
291 });
292 var oldView = $('view');
293 oldView.parentNode.replaceChild(view, oldView);
294
295 var select = $('baseline');
296 removeAllChildren(select);
297 select.appendChild(document.createElement('option'));
298 versions.forEach((version) => {
299 var option = document.createElement("option");
300 option.textContent = version.name;
301 option.version = version;
302 select.appendChild(option);
303 });
Ben Murdoch61f157c2016-09-16 13:49:30 +0100304 initializeToggleList(versions.versions, $('versionSelector'));
305 initializeToggleList(pages.values(), $('pageSelector'));
306 initializeToggleContentVisibility();
307 }
Ben Murdochc5610432016-08-08 18:44:38 +0100308
Ben Murdoch61f157c2016-09-16 13:49:30 +0100309 function initializeToggleList(items, node) {
310 var list = node.querySelector('ul');
311 removeAllChildren(list);
312 items = Array.from(items);
313 items.sort(NameComparator);
314 items.forEach((item) => {
Ben Murdochc5610432016-08-08 18:44:38 +0100315 var li = document.createElement('li');
316 var checkbox = document.createElement('input');
317 checkbox.type = 'checkbox';
Ben Murdoch61f157c2016-09-16 13:49:30 +0100318 checkbox.checked = item.enabled;
319 checkbox.item = item;
Ben Murdochc5610432016-08-08 18:44:38 +0100320 checkbox.addEventListener('click', handleToggleVersionEnable);
321 li.appendChild(checkbox);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100322 li.appendChild(document.createTextNode(item.name));
323 list.appendChild(li);
Ben Murdochc5610432016-08-08 18:44:38 +0100324 });
325 $('results').querySelectorAll('#results > .hidden').forEach((node) => {
326 toggleCssClass(node, 'hidden', false);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100327 })
328 }
329
330 function initializeToggleContentVisibility() {
331 var nodes = document.querySelectorAll('.toggleContentVisibility');
332 nodes.forEach((node) => {
333 var content = node.querySelector('.content');
334 var header = node.querySelector('h1,h2,h3');
335 if (content === undefined || header === undefined) return;
336 if (header.querySelector('input') != undefined) return;
337 var checkbox = document.createElement('input');
338 checkbox.type = 'checkbox';
339 checkbox.checked = content.className.indexOf('hidden') == -1;
340 checkbox.contentNode = content;
341 checkbox.addEventListener('click', handleToggleContentVisibility);
342 header.insertBefore(checkbox, header.childNodes[0]);
Ben Murdochc5610432016-08-08 18:44:38 +0100343 });
344 }
345
346 function showPage(firstPage) {
347 var changeSelectedEntry = selectedEntry !== undefined
348 && selectedEntry.page === selectedPage;
349 selectedPage = firstPage;
350 selectedPage.sort();
351 showPageInColumn(firstPage, 0);
352 // Show the other versions of this page in the following columns.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100353 var pageVersions = versions.getPageVersions(firstPage);
Ben Murdochc5610432016-08-08 18:44:38 +0100354 var index = 1;
355 pageVersions.forEach((page) => {
356 if (page !== firstPage) {
357 showPageInColumn(page, index);
358 index++;
359 }
360 });
361 if (changeSelectedEntry) {
362 showEntryDetail(selectedPage.getEntry(selectedEntry));
363 } else {
364 showImpactList(selectedPage);
365 }
366 }
367
368 function showPageInColumn(page, columnIndex) {
369 page.sort();
370 var showDiff = (baselineVersion === undefined && columnIndex !== 0) ||
371 (baselineVersion !== undefined && page.version !== baselineVersion);
372 var diffStatus = (td, a, b) => {};
373 if (showDiff) {
374 if (baselineVersion !== undefined) {
375 diffStatus = (td, a, b) => {
376 if (a == 0) return;
377 td.style.color = a < 0 ? '#FF0000' : '#00BB00';
378 };
379 } else {
380 diffStatus = (td, a, b) => {
381 if (a == b) return;
382 var color;
383 var ratio = a / b;
384 if (ratio > 1) {
385 ratio = Math.min(Math.round((ratio - 1) * 255 * 10), 200);
386 color = '#' + ratio.toString(16) + "0000";
387 } else {
388 ratio = Math.min(Math.round((1 - ratio) * 255 * 10), 200);
389 color = '#00' + ratio.toString(16) + "00";
390 }
391 td.style.color = color;
392 }
393 }
394 }
395
396 var column = $('column_' + columnIndex);
397 var select = $('select_' + columnIndex);
398 // Find the matching option
399 selectOption(select, (i, option) => {
400 return option.page == page
401 });
402 var table = column.querySelector("table");
403 var oldTbody = table.querySelector('tbody');
404 var tbody = document.createElement('tbody');
405 var referencePage = selectedPage;
406 page.forEachSorted(selectedPage, (parentEntry, entry, referenceEntry) => {
407 // Filter out entries that do not exist in the first column for the default
408 // view.
409 if (baselineVersion === undefined && referenceEntry &&
410 referenceEntry.time == 0) {
411 return;
412 }
413 var tr = document.createElement('tr');
414 tbody.appendChild(tr);
415 tr.entry = entry;
416 tr.parentEntry = parentEntry;
417 tr.className = parentEntry === undefined ? 'parent' : 'child';
418 // Don't show entries that do not exist on the current page or if we
419 // compare against the current page
420 if (entry !== undefined && page.version !== baselineVersion) {
421 // If we show a diff, use the baselineVersion as the referenceEntry
422 if (baselineVersion !== undefined) {
423 var baselineEntry = baselineVersion.getEntry(entry);
424 if (baselineEntry !== undefined) referenceEntry = baselineEntry
425 }
426 if (!parentEntry) {
427 var node = td(tr, '<div class="toggle">►</div>', 'position');
428 node.firstChild.addEventListener('click', handleToggleGroup);
429 } else {
430 td(tr, entry.position == 0 ? '' : entry.position, 'position');
431 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100432 addCodeSearchButton(entry,
433 td(tr, entry.name, 'name ' + entry.cssClass()));
434
Ben Murdochc5610432016-08-08 18:44:38 +0100435 diffStatus(
436 td(tr, ms(entry.time), 'value time'),
437 entry.time, referenceEntry.time);
438 diffStatus(
439 td(tr, percent(entry.timePercent), 'value time'),
440 entry.time, referenceEntry.time);
441 diffStatus(
442 td(tr, count(entry.count), 'value count'),
443 entry.count, referenceEntry.count);
444 } else if (baselineVersion !== undefined && referenceEntry
445 && page.version !== baselineVersion) {
446 // Show comparison of entry that does not exist on the current page.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100447 tr.entry = new Entry(0, referenceEntry.name);
448 tr.entry.page = page;
Ben Murdochc5610432016-08-08 18:44:38 +0100449 td(tr, '-', 'position');
450 td(tr, referenceEntry.name, 'name');
451 diffStatus(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100452 td(tr, ms(-referenceEntry.time), 'value time'),
453 -referenceEntry.time, 0);
Ben Murdochc5610432016-08-08 18:44:38 +0100454 diffStatus(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100455 td(tr, percent(-referenceEntry.timePercent), 'value time'),
456 -referenceEntry.timePercent, 0);
Ben Murdochc5610432016-08-08 18:44:38 +0100457 diffStatus(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100458 td(tr, count(-referenceEntry.count), 'value count'),
459 -referenceEntry.count, 0);
Ben Murdochc5610432016-08-08 18:44:38 +0100460 } else {
461 // Display empty entry / baseline entry
462 var showBaselineEntry = entry !== undefined;
463 if (showBaselineEntry) {
464 if (!parentEntry) {
465 var node = td(tr, '<div class="toggle">►</div>', 'position');
466 node.firstChild.addEventListener('click', handleToggleGroup);
467 } else {
468 td(tr, entry.position == 0 ? '' : entry.position, 'position');
469 }
470 td(tr, entry.name, 'name');
471 td(tr, ms(entry.time, false), 'value time');
472 td(tr, percent(entry.timePercent, false), 'value time');
473 td(tr, count(entry.count, false), 'value count');
474 } else {
475 td(tr, '-', 'position');
476 td(tr, '-', 'name');
477 td(tr, '-', 'value time');
478 td(tr, '-', 'value time');
479 td(tr, '-', 'value count');
480 }
481 }
482 });
483 table.replaceChild(tbody, oldTbody);
484 var versionSelect = column.querySelector('select.version');
485 selectOption(versionSelect, (index, option) => {
486 return option.version == page.version
487 });
488 }
489
490 function selectEntry(entry, updateSelectedPage) {
491 if (updateSelectedPage) {
492 entry = selectedPage.version.getEntry(entry);
493 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100494 var rowIndex = 0;
Ben Murdochc5610432016-08-08 18:44:38 +0100495 var needsPageSwitch = updateSelectedPage && entry.page != selectedPage;
496 // If clicked in the detail row change the first column to that page.
497 if (needsPageSwitch) showPage(entry.page);
498 var childNodes = $('column_0').querySelector('.list tbody').childNodes;
499 for (var i = 0; i < childNodes.length; i++) {
500 if (childNodes[i].entry.name == entry.name) {
501 rowIndex = i;
502 break;
503 }
504 }
505 var firstEntry = childNodes[rowIndex].entry;
506 if (rowIndex) {
507 if (firstEntry.parent) showGroup(firstEntry.parent);
508 }
509 // Deselect all
510 $('view').querySelectorAll('.list tbody tr').forEach((tr) => {
511 toggleCssClass(tr, 'selected', false);
512 });
513 // Select the entry row
514 $('view').querySelectorAll("tbody").forEach((body) => {
515 var row = body.childNodes[rowIndex];
516 if (!row) return;
517 toggleCssClass(row, 'selected', row.entry && row.entry.name ==
518 firstEntry.name);
519 });
520 if (updateSelectedPage) {
521 entry = selectedEntry.page.version.getEntry(entry);
522 }
523 selectedEntry = entry;
524 showEntryDetail(entry);
525 }
526
527 function showEntryDetail(entry) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100528 showVersionDetails(entry);
529 showPageDetails(entry);
530 showImpactList(entry.page);
531 showGraphs(entry.page);
532 }
533
534 function showVersionDetails(entry) {
Ben Murdochc5610432016-08-08 18:44:38 +0100535 var table, tbody, entries;
536 table = $('detailView').querySelector('.versionDetailTable');
537 tbody = document.createElement('tbody');
538 if (entry !== undefined) {
539 $('detailView').querySelector('.versionDetail h3 span').innerHTML =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100540 entry.name + ' in ' + entry.page.name;
541 entries = versions.getPageVersions(entry.page).map(
Ben Murdochc5610432016-08-08 18:44:38 +0100542 (page) => {
543 return page.get(entry.name)
544 });
545 entries.sort((a, b) => {
546 return a.time - b.time
547 });
548 entries.forEach((pageEntry) => {
549 if (pageEntry === undefined) return;
550 var tr = document.createElement('tr');
551 if (pageEntry == entry) tr.className += 'selected';
552 tr.entry = pageEntry;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100553 var isBaselineEntry = pageEntry.page.version == baselineVersion;
Ben Murdochc5610432016-08-08 18:44:38 +0100554 td(tr, pageEntry.page.version.name, 'version');
Ben Murdoch61f157c2016-09-16 13:49:30 +0100555 td(tr, ms(pageEntry.time, !isBaselineEntry), 'value time');
556 td(tr, percent(pageEntry.timePercent, !isBaselineEntry), 'value time');
557 td(tr, count(pageEntry.count, !isBaselineEntry), 'value count');
Ben Murdochc5610432016-08-08 18:44:38 +0100558 tbody.appendChild(tr);
559 });
560 }
561 table.replaceChild(tbody, table.querySelector('tbody'));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100562 }
Ben Murdochc5610432016-08-08 18:44:38 +0100563
Ben Murdoch61f157c2016-09-16 13:49:30 +0100564 function showPageDetails(entry) {
565 var table, tbody, entries;
Ben Murdochc5610432016-08-08 18:44:38 +0100566 table = $('detailView').querySelector('.pageDetailTable');
567 tbody = document.createElement('tbody');
Ben Murdoch61f157c2016-09-16 13:49:30 +0100568 if (entry === undefined) {
569 table.replaceChild(tbody, table.querySelector('tbody'));
570 return;
Ben Murdochc5610432016-08-08 18:44:38 +0100571 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100572 var version = entry.page.version;
573 var showDiff = version !== baselineVersion;
574 $('detailView').querySelector('.pageDetail h3 span').innerHTML =
575 version.name;
576 entries = version.pages.map((page) => {
577 if (!page.enabled) return;
578 return page.get(entry.name)
579 });
580 entries.sort((a, b) => {
581 var cmp = b.timePercent - a.timePercent;
582 if (cmp.toFixed(1) == 0) return b.time - a.time;
583 return cmp
584 });
585 entries.forEach((pageEntry) => {
586 if (pageEntry === undefined) return;
587 var tr = document.createElement('tr');
588 if (pageEntry === entry) tr.className += 'selected';
589 tr.entry = pageEntry;
590 td(tr, pageEntry.page.name, 'name');
591 td(tr, ms(pageEntry.time, showDiff), 'value time');
592 td(tr, percent(pageEntry.timePercent, showDiff), 'value time');
593 td(tr, percent(pageEntry.timePercentPerEntry, showDiff),
594 'value time hideNoDiff');
595 td(tr, count(pageEntry.count, showDiff), 'value count');
596 tbody.appendChild(tr);
597 });
598 // show the total for all pages
599 var tds = table.querySelectorAll('tfoot td');
600 tds[1].innerHTML = ms(entry.getTimeImpact(), showDiff);
601 // Only show the percentage total if we are in diff mode:
602 tds[2].innerHTML = percent(entry.getTimePercentImpact(), showDiff);
603 tds[3].innerHTML = '';
604 tds[4].innerHTML = count(entry.getCountImpact(), showDiff);
Ben Murdochc5610432016-08-08 18:44:38 +0100605 table.replaceChild(tbody, table.querySelector('tbody'));
Ben Murdochc5610432016-08-08 18:44:38 +0100606 }
607
608 function showImpactList(page) {
609 var impactView = $('detailView').querySelector('.impactView');
610 impactView.querySelector('h3 span').innerHTML = page.version.name;
611
612 var table = impactView.querySelector('table');
613 var tbody = document.createElement('tbody');
614 var version = page.version;
615 var entries = version.allEntries();
616 if (selectedEntry !== undefined && selectedEntry.isGroup) {
617 impactView.querySelector('h3 span').innerHTML += " " + selectedEntry.name;
618 entries = entries.filter((entry) => {
619 return entry.name == selectedEntry.name ||
620 (entry.parent && entry.parent.name == selectedEntry.name)
621 });
622 }
623 var isCompareView = baselineVersion !== undefined;
624 entries = entries.filter((entry) => {
625 if (isCompareView) {
626 var impact = entry.getTimeImpact();
627 return impact < -1 || 1 < impact
628 }
629 return entry.getTimePercentImpact() > 0.1;
630 });
631 entries.sort((a, b) => {
632 var cmp = b.getTimePercentImpact() - a.getTimePercentImpact();
633 if (isCompareView || cmp.toFixed(1) == 0) {
634 return b.getTimeImpact() - a.getTimeImpact();
635 }
636 return cmp
637 });
638 entries.forEach((entry) => {
639 var tr = document.createElement('tr');
640 tr.entry = entry;
641 td(tr, entry.name, 'name');
642 td(tr, ms(entry.getTimeImpact()), 'value time');
643 var percentImpact = entry.getTimePercentImpact();
644 td(tr, percentImpact > 1000 ? '-' : percent(percentImpact), 'value time');
645 var topPages = entry.getPagesByPercentImpact().slice(0, 3)
646 .map((each) => {
647 return each.name + ' (' + percent(each.getEntry(entry).timePercent) +
648 ')'
649 });
650 td(tr, topPages.join(', '), 'name');
651 tbody.appendChild(tr);
652 });
653 table.replaceChild(tbody, table.querySelector('tbody'));
654 }
655
Ben Murdoch61f157c2016-09-16 13:49:30 +0100656 function showGraphs(page) {
657 var groups = page.groups.slice();
658 // Sort groups by the biggest impact
659 groups.sort((a, b) => {
660 return b.getTimeImpact() - a.getTimeImpact();
661 });
Ben Murdochc5610432016-08-08 18:44:38 +0100662 if (selectedGroup == undefined) {
663 selectedGroup = groups[0];
664 } else {
665 groups = groups.filter(each => each.name != selectedGroup.name);
666 groups.unshift(selectedGroup);
667 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100668 showPageGraph(groups, page);
669 showVersionGraph(groups, page);
670 showPageVersionGraph(groups, page);
671 }
672
673 function getGraphDataTable(groups) {
Ben Murdochc5610432016-08-08 18:44:38 +0100674 var dataTable = new google.visualization.DataTable();
675 dataTable.addColumn('string', 'Name');
676 groups.forEach(group => {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100677 var column = dataTable.addColumn('number', group.name.substring(6));
Ben Murdochc5610432016-08-08 18:44:38 +0100678 dataTable.setColumnProperty(column, 'group', group);
679 });
Ben Murdoch61f157c2016-09-16 13:49:30 +0100680 return dataTable;
681 }
682
683 var selectedGroup;
684 function showPageGraph(groups, page) {
685 var isDiffView = baselineVersion !== undefined;
686 var dataTable = getGraphDataTable(groups);
Ben Murdochc5610432016-08-08 18:44:38 +0100687 // Calculate the average row
688 var row = ['Average'];
689 groups.forEach((group) => {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100690 if (isDiffView) {
691 row.push(group.isTotal ? 0 : group.getAverageTimeImpact());
692 } else {
693 row.push(group.isTotal ? 0 : group.getTimeImpact());
694 }
Ben Murdochc5610432016-08-08 18:44:38 +0100695 });
696 dataTable.addRow(row);
697 // Sort the pages by the selected group.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100698 var pages = page.version.pages.filter(page => page.enabled);
699 function sumDiff(page) {
700 var sum = 0;
701 groups.forEach(group => {
702 var value = group.getTimePercentImpact() -
703 page.getEntry(group).timePercent;
704 sum += value * value;
705 });
706 return sum;
707 }
708 if (isDiffView) {
709 pages.sort((a, b) => {
710 return b.getEntry(selectedGroup).time-
711 a.getEntry(selectedGroup).time;
712 });
713 } else {
714 pages.sort((a, b) => {
715 return b.getEntry(selectedGroup).timePercent -
716 a.getEntry(selectedGroup).timePercent;
717 });
718 }
719 // Sort by sum of squared distance to the average.
720 // pages.sort((a, b) => {
721 // return a.distanceFromTotalPercent() - b.distanceFromTotalPercent();
722 // });
Ben Murdochc5610432016-08-08 18:44:38 +0100723 // Calculate the entries for the pages
724 pages.forEach((page) => {
725 row = [page.name];
726 groups.forEach((group) => {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100727 row.push(group.isTotal ? 0 : page.getEntry(group).time);
Ben Murdochc5610432016-08-08 18:44:38 +0100728 });
Ben Murdoch61f157c2016-09-16 13:49:30 +0100729 var rowIndex = dataTable.addRow(row);
730 dataTable.setRowProperty(rowIndex, 'page', page);
Ben Murdochc5610432016-08-08 18:44:38 +0100731 });
Ben Murdoch61f157c2016-09-16 13:49:30 +0100732 renderGraph('Pages for ' + page.version.name, groups, dataTable,
733 'pageGraph', isDiffView ? true : 'percent');
734 }
Ben Murdochc5610432016-08-08 18:44:38 +0100735
Ben Murdoch61f157c2016-09-16 13:49:30 +0100736 function showVersionGraph(groups, page) {
737 var dataTable = getGraphDataTable(groups);
738 var row;
739 var vs = versions.versions.filter(version => version.enabled);
740 vs.sort((a, b) => {
741 return b.getEntry(selectedGroup).getTimeImpact() -
742 a.getEntry(selectedGroup).getTimeImpact();
743 });
744 // Calculate the entries for the versions
745 vs.forEach((version) => {
746 row = [version.name];
747 groups.forEach((group) => {
748 row.push(group.isTotal ? 0 : version.getEntry(group).getTimeImpact());
749 });
750 var rowIndex = dataTable.addRow(row);
751 dataTable.setRowProperty(rowIndex, 'page', page);
752 });
753 renderGraph('Versions Total Time over all Pages', groups, dataTable,
754 'versionGraph', true);
755 }
756
757 function showPageVersionGraph(groups, page) {
758 var dataTable = getGraphDataTable(groups);
759 var row;
760 var vs = versions.getPageVersions(page);
761 vs.sort((a, b) => {
762 return b.getEntry(selectedGroup).time - a.getEntry(selectedGroup).time;
763 });
764 // Calculate the entries for the versions
765 vs.forEach((page) => {
766 row = [page.version.name];
767 groups.forEach((group) => {
768 row.push(group.isTotal ? 0 : page.getEntry(group).time);
769 });
770 var rowIndex = dataTable.addRow(row);
771 dataTable.setRowProperty(rowIndex, 'page', page);
772 });
773 renderGraph('Versions for ' + page.name, groups, dataTable,
774 'pageVersionGraph', true);
775 }
776
777 function renderGraph(title, groups, dataTable, id, isStacked) {
778 var isDiffView = baselineVersion !== undefined;
779 var formatter = new google.visualization.NumberFormat({
780 suffix: (isDiffView ? 'msΔ' : 'ms'),
781 negativeColor: 'red',
782 groupingSymbol: "'"
783 });
784 for (var i = 1; i < dataTable.getNumberOfColumns(); i++) {
785 formatter.format(dataTable, i);
786 }
787 var height = 85 + 28 * dataTable.getNumberOfRows();
Ben Murdochc5610432016-08-08 18:44:38 +0100788 var options = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100789 isStacked: isStacked,
790 height: height,
Ben Murdochc5610432016-08-08 18:44:38 +0100791 hAxis: {
Ben Murdochc5610432016-08-08 18:44:38 +0100792 minValue: 0,
793 },
Ben Murdoch61f157c2016-09-16 13:49:30 +0100794 animation:{
795 duration: 500,
796 easing: 'out',
797 },
Ben Murdochc5610432016-08-08 18:44:38 +0100798 vAxis: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100799 },
800 explorer: {
801 actions: ['dragToZoom', 'rightClickToReset'],
802 maxZoomIn: 0.01
803 },
804 legend: {position:'top', textStyle:{fontSize: '16px'}},
805 chartArea: {left:200, top:50, width:'98%', height:'80%'},
806 colors: groups.map(each => each.color)
Ben Murdochc5610432016-08-08 18:44:38 +0100807 };
Ben Murdoch61f157c2016-09-16 13:49:30 +0100808 var parentNode = $(id);
809 parentNode.querySelector('h2>span, h3>span').innerHTML = title;
810 var graphNode = parentNode.querySelector('.content');
811
812 var chart = graphNode.chart;
813 if (chart === undefined) {
814 chart = graphNode.chart = new google.visualization.BarChart(graphNode);
815 } else {
816 google.visualization.events.removeAllListeners(chart);
Ben Murdochc5610432016-08-08 18:44:38 +0100817 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100818 google.visualization.events.addListener(chart, 'select', selectHandler);
819 function getChartEntry(selection) {
820 if (!selection) return undefined;
821 var column = selection.column;
822 if (column == undefined) return undefined;
823 var selectedGroup = dataTable.getColumnProperty(column, 'group');
824 var row = selection.row;
825 if (row == null) return selectedGroup;
826 var page = dataTable.getRowProperty(row, 'page');
827 if (!page) return selectedGroup;
828 return page.getEntry(selectedGroup);
829 }
830 function selectHandler() {
831 selectedGroup = getChartEntry(chart.getSelection()[0])
832 if (!selectedGroup) return;
833 selectEntry(selectedGroup, true);
834 }
835
836 // Make our global tooltips work
837 google.visualization.events.addListener(chart, 'onmouseover', mouseOverHandler);
838 function mouseOverHandler(selection) {
839 graphNode.entry = getChartEntry(selection);
840 }
841 chart.draw(dataTable, options);
Ben Murdochc5610432016-08-08 18:44:38 +0100842 }
843
844 function showGroup(entry) {
845 toggleGroup(entry, true);
846 }
847
848 function toggleGroup(group, show) {
849 $('view').querySelectorAll(".child").forEach((tr) => {
850 var entry = tr.parentEntry;
851 if (!entry) return;
852 if (entry.name !== group.name) return;
853 toggleCssClass(tr, 'visible', show);
854 });
855 }
856
857 function showPopover(entry) {
858 var popover = $('popover');
859 popover.querySelector('td.name').innerHTML = entry.name;
860 popover.querySelector('td.page').innerHTML = entry.page.name;
861 setPopoverDetail(popover, entry, '');
862 popover.querySelector('table').className = "";
863 if (baselineVersion !== undefined) {
864 entry = baselineVersion.getEntry(entry);
865 setPopoverDetail(popover, entry, '.compare');
866 popover.querySelector('table').className = "compare";
867 }
868 }
869
870 function setPopoverDetail(popover, entry, prefix) {
871 var node = (name) => popover.querySelector(prefix + name);
872 if (entry == undefined) {
873 node('.version').innerHTML = baselineVersion.name;
874 node('.time').innerHTML = '-';
875 node('.timeVariance').innerHTML = '-';
876 node('.percent').innerHTML = '-';
Ben Murdoch61f157c2016-09-16 13:49:30 +0100877 node('.percentPerEntry').innerHTML = '-';
Ben Murdochc5610432016-08-08 18:44:38 +0100878 node('.percentVariance').innerHTML = '-';
879 node('.count').innerHTML = '-';
880 node('.countVariance').innerHTML = '-';
881 node('.timeImpact').innerHTML = '-';
882 node('.timePercentImpact').innerHTML = '-';
883 } else {
884 node('.version').innerHTML = entry.page.version.name;
885 node('.time').innerHTML = ms(entry._time, false);
886 node('.timeVariance').innerHTML
887 = percent(entry.timeVariancePercent, false);
888 node('.percent').innerHTML = percent(entry.timePercent, false);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100889 node('.percentPerEntry').innerHTML
890 = percent(entry.timePercentPerEntry, false);
Ben Murdochc5610432016-08-08 18:44:38 +0100891 node('.percentVariance').innerHTML
892 = percent(entry.timePercentVariancePercent, false);
893 node('.count').innerHTML = count(entry._count, false);
894 node('.countVariance').innerHTML
895 = percent(entry.timeVariancePercent, false);
896 node('.timeImpact').innerHTML
897 = ms(entry.getTimeImpact(false), false);
898 node('.timePercentImpact').innerHTML
899 = percent(entry.getTimeImpactVariancePercent(false), false);
900 }
901 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100902 </script>
903 <script type="text/javascript">
904 "use strict"
905 // =========================================================================
Ben Murdochc5610432016-08-08 18:44:38 +0100906 // Helpers
907 function $(id) {
908 return document.getElementById(id)
909 }
910
911 function removeAllChildren(node) {
912 while (node.firstChild) {
913 node.removeChild(node.firstChild);
914 }
915 }
916
917 function selectOption(select, match) {
918 var options = select.options;
919 for (var i = 0; i < options.length; i++) {
920 if (match(i, options[i])) {
921 select.selectedIndex = i;
922 return;
923 }
924 }
925 }
926
Ben Murdoch61f157c2016-09-16 13:49:30 +0100927 function addCodeSearchButton(entry, node) {
928 if (entry.isGroup) return;
929 var button = document.createElement("div");
930 button.innerHTML = '?'
931 button.className = "codeSearch"
932 button.addEventListener('click', handleCodeSearch);
933 node.appendChild(button);
934 return node;
935 }
936
Ben Murdochc5610432016-08-08 18:44:38 +0100937 function td(tr, content, className) {
938 var td = document.createElement("td");
939 td.innerHTML = content;
940 td.className = className
941 tr.appendChild(td);
942 return td
943 }
944
945 function nodeIndex(node) {
946 var children = node.parentNode.childNodes,
947 i = 0;
948 for (; i < children.length; i++) {
949 if (children[i] == node) {
950 return i;
951 }
952 }
953 return -1;
954 }
955
956 function toggleCssClass(node, cssClass, toggleState) {
957 var index = -1;
958 var classes;
959 if (node.className != undefined) {
960 classes = node.className.split(' ');
961 index = classes.indexOf(cssClass);
962 }
963 if (index == -1) {
964 if (toggleState === false) return;
965 node.className += ' ' + cssClass;
966 return;
967 }
968 if (toggleState === true) return;
969 classes.splice(index, 1);
970 node.className = classes.join(' ');
971 }
972
Ben Murdoch61f157c2016-09-16 13:49:30 +0100973 function NameComparator(a, b) {
974 if (a.name > b.name) return 1;
975 if (a.name < b.name) return -1;
976 return 0
977 }
978
Ben Murdochc5610432016-08-08 18:44:38 +0100979 function diffSign(value, digits, unit, showDiff) {
980 if (showDiff === false || baselineVersion == undefined) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100981 if (value === undefined) return '';
Ben Murdochc5610432016-08-08 18:44:38 +0100982 return value.toFixed(digits) + unit;
983 }
984 return (value >= 0 ? '+' : '') + value.toFixed(digits) + unit + 'Δ';
985 }
986
987 function ms(value, showDiff) {
988 return diffSign(value, 1, 'ms', showDiff);
989 }
990
991 function count(value, showDiff) {
992 return diffSign(value, 0, '#', showDiff);
993 }
994
995 function percent(value, showDiff) {
996 return diffSign(value, 1, '%', showDiff);
997 }
998
Ben Murdoch61f157c2016-09-16 13:49:30 +0100999 </script>
1000 <script type="text/javascript">
1001 "use strict"
Ben Murdochc5610432016-08-08 18:44:38 +01001002 // =========================================================================
1003 // EventHandlers
1004 function handleBodyLoad() {
1005 $('uploadInput').focus();
1006 }
1007
1008 function handleLoadFile() {
1009 var files = document.getElementById("uploadInput").files;
1010 var file = files[0];
1011 var reader = new FileReader();
1012
1013 reader.onload = function(evt) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001014 pages = new Pages();
Ben Murdochc5610432016-08-08 18:44:38 +01001015 versions = Versions.fromJSON(JSON.parse(this.result));
1016 initialize()
1017 showPage(versions.versions[0].pages[0]);
1018 }
1019 reader.readAsText(file);
1020 }
1021
1022 function handleToggleGroup(event) {
1023 var group = event.target.parentNode.parentNode.entry;
1024 toggleGroup(selectedPage.get(group.name));
1025 }
1026
1027 function handleSelectPage(select, event) {
1028 var option = select.options[select.selectedIndex];
1029 if (select.id == "select_0") {
1030 showPage(option.page);
1031 } else {
1032 var columnIndex = select.id.split('_')[1];
1033 showPageInColumn(option.page, columnIndex);
1034 }
1035 }
1036
1037 function handleSelectVersion(select, event) {
1038 var option = select.options[select.selectedIndex];
1039 var version = option.version;
1040 if (select.id == "selectVersion_0") {
1041 var page = version.get(selectedPage.name);
1042 showPage(page);
1043 } else {
1044 var columnIndex = select.id.split('_')[1];
1045 var pageSelect = $('select_' + columnIndex);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001046 var page = pageSelect.options[pageSelect.selectedIndex].page;
Ben Murdochc5610432016-08-08 18:44:38 +01001047 page = version.get(page.name);
1048 showPageInColumn(page, columnIndex);
1049 }
1050 }
1051
1052 function handleSelectDetailRow(table, event) {
1053 if (event.target.tagName != 'TD') return;
1054 var tr = event.target.parentNode;
1055 if (tr.tagName != 'TR') return;
1056 if (tr.entry === undefined) return;
1057 selectEntry(tr.entry, true);
1058 }
1059
1060 function handleSelectRow(table, event, fromDetail) {
1061 if (event.target.tagName != 'TD') return;
1062 var tr = event.target.parentNode;
1063 if (tr.tagName != 'TR') return;
1064 if (tr.entry === undefined) return;
1065 selectEntry(tr.entry, false);
1066 }
1067
1068 function handleSelectBaseline(select, event) {
1069 var option = select.options[select.selectedIndex];
Ben Murdoch61f157c2016-09-16 13:49:30 +01001070 baselineVersion = option.version;
1071 var showingDiff = baselineVersion !== undefined;
1072 var body = $('body');
1073 toggleCssClass(body, 'diff', showingDiff);
1074 toggleCssClass(body, 'noDiff', !showingDiff);
Ben Murdochc5610432016-08-08 18:44:38 +01001075 showPage(selectedPage);
1076 if (selectedEntry === undefined) return;
1077 selectEntry(selectedEntry, true);
1078 }
1079
Ben Murdoch61f157c2016-09-16 13:49:30 +01001080 function findEntry(event) {
1081 var target = event.target;
1082 while (target.entry === undefined) {
1083 target = target.parentNode;
1084 if (!target) return undefined;
1085 }
1086 return target.entry;
1087 }
1088
Ben Murdochc5610432016-08-08 18:44:38 +01001089 function handleUpdatePopover(event) {
1090 var popover = $('popover');
1091 popover.style.left = event.pageX + 'px';
1092 popover.style.top = event.pageY + 'px';
Ben Murdoch61f157c2016-09-16 13:49:30 +01001093 popover.style.display = 'none';
Ben Murdochc5610432016-08-08 18:44:38 +01001094 popover.style.display = event.shiftKey ? 'block' : 'none';
Ben Murdoch61f157c2016-09-16 13:49:30 +01001095 var entry = findEntry(event);
1096 if (entry === undefined) return;
1097 showPopover(entry);
Ben Murdochc5610432016-08-08 18:44:38 +01001098 }
1099
1100 function handleToggleVersionEnable(event) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001101 var item = this.item ;
1102 if (item === undefined) return;
1103 item .enabled = this.checked;
Ben Murdochc5610432016-08-08 18:44:38 +01001104 initialize();
1105 var page = selectedPage;
1106 if (page === undefined || !page.version.enabled) {
1107 page = versions.getEnabledPage(page.name);
1108 }
1109 showPage(page);
1110 }
1111
Ben Murdoch61f157c2016-09-16 13:49:30 +01001112 function handleToggleContentVisibility(event) {
1113 var content = event.target.contentNode;
1114 toggleCssClass(content, 'hidden');
1115 }
Ben Murdochc5610432016-08-08 18:44:38 +01001116
Ben Murdoch61f157c2016-09-16 13:49:30 +01001117 function handleCodeSearch(event) {
1118 var entry = findEntry(event);
1119 if (entry === undefined) return;
1120 var url = "https://cs.chromium.org/search/?sq=package:chromium&type=cs&q=";
1121 name = entry.name;
1122 if (name.startsWith("API_")) {
1123 name = name.substring(4);
1124 }
1125 url += encodeURIComponent(name) + "+file:src/v8/src";
1126 window.open(url,'_blank');
1127 }
1128 </script>
1129 <script type="text/javascript">
1130 "use strict"
1131 // =========================================================================
Ben Murdochc5610432016-08-08 18:44:38 +01001132 class Versions {
1133 constructor() {
1134 this.versions = [];
1135 }
1136 add(version) {
1137 this.versions.push(version)
1138 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001139 getPageVersions(page) {
Ben Murdochc5610432016-08-08 18:44:38 +01001140 var result = [];
1141 this.versions.forEach((version) => {
1142 if (!version.enabled) return;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001143 var versionPage = version.get(page.name);
1144 if (versionPage !== undefined) result.push(versionPage);
Ben Murdochc5610432016-08-08 18:44:38 +01001145 });
1146 return result;
1147 }
1148 get length() {
1149 return this.versions.length
1150 }
1151 get(index) {
1152 return this.versions[index]
1153 };
1154 forEach(f) {
1155 this.versions.forEach(f);
1156 }
1157 sort() {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001158 this.versions.sort(NameComparator);
Ben Murdochc5610432016-08-08 18:44:38 +01001159 }
1160 getEnabledPage(name) {
1161 for (var i = 0; i < this.versions.length; i++) {
1162 var version = this.versions[i];
1163 if (!version.enabled) continue;
1164 var page = version.get(name);
1165 if (page !== undefined) return page;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001166 }
Ben Murdochc5610432016-08-08 18:44:38 +01001167 }
1168 }
1169 Versions.fromJSON = function(json) {
1170 var versions = new Versions();
1171 for (var version in json) {
1172 versions.add(Version.fromJSON(version, json[version]));
1173 }
1174 versions.sort();
1175 return versions;
1176 }
1177
1178 class Version {
1179 constructor(name) {
1180 this.name = name;
1181 this.enabled = true;
1182 this.pages = [];
1183 }
1184 add(page) {
1185 this.pages.push(page);
1186 }
1187 indexOf(name) {
1188 for (var i = 0; i < this.pages.length; i++) {
1189 if (this.pages[i].name == name) return i;
1190 }
1191 return -1;
1192 }
1193 get(name) {
1194 var index = this.indexOf(name);
1195 if (0 <= index) return this.pages[index];
1196 return undefined
1197 }
1198 get length() {
1199 return this.versions.length
1200 }
1201 getEntry(entry) {
1202 if (entry === undefined) return undefined;
1203 var page = this.get(entry.page.name);
1204 if (page === undefined) return undefined;
1205 return page.get(entry.name);
1206 }
1207 forEachEntry(fun) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001208 this.forEachPage((page) => {
Ben Murdochc5610432016-08-08 18:44:38 +01001209 page.forEach(fun);
1210 });
1211 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001212 forEachPage(fun) {
1213 this.pages.forEach((page) => {
1214 if (!page.enabled) return;
1215 fun(page);
1216 })
1217 }
Ben Murdochc5610432016-08-08 18:44:38 +01001218 allEntries() {
1219 var map = new Map();
1220 this.forEachEntry((group, entry) => {
1221 if (!map.has(entry.name)) map.set(entry.name, entry);
1222 });
1223 return Array.from(map.values());
1224 }
1225 getTotalValue(name, property) {
1226 if (name === undefined) name = this.pages[0].total.name;
1227 var sum = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001228 this.forEachPage((page) => {
Ben Murdochc5610432016-08-08 18:44:38 +01001229 var entry = page.get(name);
1230 if (entry !== undefined) sum += entry[property];
1231 });
1232 return sum;
1233 }
1234 getTotalTime(name, showDiff) {
1235 return this.getTotalValue(name, showDiff === false ? '_time' : 'time');
1236 }
1237 getTotalTimePercent(name, showDiff) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001238 if (baselineVersion === undefined || showDiff === false) {
Ben Murdochc5610432016-08-08 18:44:38 +01001239 // Return the overall average percent of the given entry name.
1240 return this.getTotalValue(name, 'time') /
1241 this.getTotalTime('Group-Total') * 100;
1242 }
1243 // Otherwise return the difference to the sum of the baseline version.
1244 var baselineValue = baselineVersion.getTotalTime(name, false);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001245 var total = this.getTotalValue(name, '_time');
1246 return (total / baselineValue - 1) * 100;
Ben Murdochc5610432016-08-08 18:44:38 +01001247 }
1248 getTotalTimeVariance(name, showDiff) {
1249 // Calculate the overall error for a given entry name
1250 var sum = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001251 this.forEachPage((page) => {
Ben Murdochc5610432016-08-08 18:44:38 +01001252 var entry = page.get(name);
1253 if (entry === undefined) return;
1254 sum += entry.timeVariance * entry.timeVariance;
1255 });
1256 return Math.sqrt(sum);
1257 }
1258 getTotalTimeVariancePercent(name, showDiff) {
1259 return this.getTotalTimeVariance(name, showDiff) /
1260 this.getTotalTime(name, showDiff) * 100;
1261 }
1262 getTotalCount(name, showDiff) {
1263 return this.getTotalValue(name, showDiff === false ? '_count' : 'count');
1264 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001265 getAverageTimeImpact(name, showDiff) {
1266 return this.getTotalTime(name, showDiff) / this.pages.length;
1267 }
Ben Murdochc5610432016-08-08 18:44:38 +01001268 getPagesByPercentImpact(name) {
1269 var sortedPages =
1270 this.pages.filter((each) => {
1271 return each.get(name) !== undefined
1272 });
1273 sortedPages.sort((a, b) => {
1274 return b.get(name).timePercent - a.get(name).timePercent;
1275 });
1276 return sortedPages;
1277 }
1278 sort() {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001279 this.pages.sort(NameComparator)
Ben Murdochc5610432016-08-08 18:44:38 +01001280 }
1281 }
1282 Version.fromJSON = function(name, data) {
1283 var version = new Version(name);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001284 for (var pageName in data) {
1285 version.add(PageVersion.fromJSON(version, pageName, data[pageName]));
Ben Murdochc5610432016-08-08 18:44:38 +01001286 }
1287 version.sort();
1288 return version;
1289 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001290
1291 class Pages extends Map {
1292 get(name) {
1293 if (name.indexOf('www.') == 0) {
1294 name = name.substring(4);
1295 }
1296 if (!this.has(name)) {
1297 this.set(name, new Page(name));
1298 }
1299 return super.get(name);
1300 }
1301 }
Ben Murdochc5610432016-08-08 18:44:38 +01001302
1303 class Page {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001304 constructor(name) {
Ben Murdochc5610432016-08-08 18:44:38 +01001305 this.name = name;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001306 this.enabled = true;
1307 this.versions = [];
1308 }
1309 add(page) {
1310 this.versions.push(page);
1311 }
1312 }
1313
1314 class PageVersion {
1315 constructor(version, page) {
1316 this.page = page;
1317 this.page.add(this);
1318 this.total = new GroupedEntry('Total', /.*Total.*/, '#BBB');
1319 this.total.isTotal = true;
1320 this.unclassified = new UnclassifiedEntry(this, "#000")
Ben Murdochc5610432016-08-08 18:44:38 +01001321 this.groups = [
1322 this.total,
Ben Murdoch61f157c2016-09-16 13:49:30 +01001323 new GroupedEntry('IC', /.*IC.*/, "#3366CC"),
Ben Murdochc5610432016-08-08 18:44:38 +01001324 new GroupedEntry('Optimize',
Ben Murdoch61f157c2016-09-16 13:49:30 +01001325 /StackGuard|.*Optimize.*|.*Deoptimize.*|Recompile.*/, "#DC3912"),
1326 new GroupedEntry('Compile', /.*Compile.*/, "#FFAA00"),
1327 new GroupedEntry('Parse', /.*Parse.*/, "#FF6600"),
1328 new GroupedEntry('Callback', /.*Callback$/, "#109618"),
1329 new GroupedEntry('API', /.*API.*/, "#990099"),
1330 new GroupedEntry('GC', /GC|AllocateInTargetSpace/, "#0099C6"),
1331 new GroupedEntry('JavaScript', /JS_Execution/, "#DD4477"),
1332 new GroupedEntry('Runtime', /.*/, "#88BB00"),
Ben Murdochc5610432016-08-08 18:44:38 +01001333 this.unclassified
1334 ];
1335 this.entryDict = new Map();
1336 this.groups.forEach((entry) => {
1337 entry.page = this;
1338 this.entryDict.set(entry.name, entry);
1339 });
1340 this.version = version;
1341 }
1342 add(entry) {
1343 entry.page = this;
1344 this.entryDict.set(entry.name, entry);
1345 var added = false;
1346 this.groups.forEach((group) => {
1347 if (!added) added = group.add(entry);
1348 });
1349 if (added) return;
1350 this.unclassified.push(entry);
1351 }
1352 get(name) {
1353 return this.entryDict.get(name)
1354 }
1355 getEntry(entry) {
1356 if (entry === undefined) return undefined;
1357 return this.get(entry.name);
1358 }
1359 get length() {
1360 return this.versions.length
1361 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001362 get name() { return this.page.name }
1363 get enabled() { return this.page.enabled }
Ben Murdochc5610432016-08-08 18:44:38 +01001364 forEachSorted(referencePage, func) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001365 // Iterate over all the entries in the order they appear on the
1366 // reference page.
Ben Murdochc5610432016-08-08 18:44:38 +01001367 referencePage.forEach((parent, referenceEntry) => {
1368 var entry;
1369 if (parent) parent = this.entryDict.get(parent.name);
1370 if (referenceEntry) entry = this.entryDict.get(referenceEntry.name);
1371 func(parent, entry, referenceEntry);
1372 });
1373 }
1374 forEach(fun) {
1375 this.forEachGroup((group) => {
1376 fun(undefined, group);
1377 group.forEach((entry) => {
1378 fun(group, entry)
1379 });
1380 });
1381 }
1382 forEachGroup(fun) {
1383 this.groups.forEach(fun)
1384 }
1385 sort() {
1386 this.groups.sort((a, b) => {
1387 return b.time - a.time;
1388 });
1389 this.groups.forEach((group) => {
1390 group.sort()
1391 });
1392 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001393 distanceFromTotalPercent() {
1394 var sum = 0;
1395 this.groups.forEach(group => {
1396 if (group == this.total) return;
1397 var value = group.getTimePercentImpact() -
1398 this.getEntry(group).timePercent;
1399 sum += value * value;
1400 });
1401 return sum;
Ben Murdochc5610432016-08-08 18:44:38 +01001402 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001403 }
1404 PageVersion.fromJSON = function(version, name, data) {
1405 var page = new PageVersion(version, pages.get(name));
Ben Murdochc5610432016-08-08 18:44:38 +01001406 for (var i = 0; i < data.length; i++) {
1407 page.add(Entry.fromJSON(i, data[data.length - i - 1]));
1408 }
1409 page.sort();
1410 return page
1411 }
1412
1413
1414 class Entry {
1415 constructor(position, name, time, timeVariance, timeVariancePercent,
1416 count,
1417 countVariance, countVariancePercent) {
1418 this.position = position;
1419 this.name = name;
1420 this._time = time;
1421 this._timeVariance = timeVariance;
1422 this._timeVariancePercent = timeVariancePercent;
1423 this._count = count;
1424 this.countVariance = countVariance;
1425 this.countVariancePercent = countVariancePercent;
1426 this.page = undefined;
1427 this.parent = undefined;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001428 this.isTotal = false;
Ben Murdochc5610432016-08-08 18:44:38 +01001429 }
1430 getCompareWithBaseline(value, property) {
1431 if (baselineVersion == undefined) return value;
1432 var baselineEntry = baselineVersion.getEntry(this);
1433 if (!baselineEntry) return value;
1434 if (baselineVersion === this.page.version) return value;
1435 return value - baselineEntry[property];
1436 }
1437 cssClass() {
1438 return ''
1439 }
1440 get time() {
1441 return this.getCompareWithBaseline(this._time, '_time');
1442 }
1443 get count() {
1444 return this.getCompareWithBaseline(this._count, '_count');
1445 }
1446 get timePercent() {
1447 var value = this._time / this.page.total._time * 100;
1448 if (baselineVersion == undefined) return value;
1449 var baselineEntry = baselineVersion.getEntry(this);
1450 if (!baselineEntry) return value;
1451 if (baselineVersion === this.page.version) return value;
1452 return (this._time - baselineEntry._time) / this.page.total._time *
1453 100;
1454 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001455 get timePercentPerEntry() {
1456 var value = this._time / this.page.total._time * 100;
1457 if (baselineVersion == undefined) return value;
1458 var baselineEntry = baselineVersion.getEntry(this);
1459 if (!baselineEntry) return value;
1460 if (baselineVersion === this.page.version) return value;
1461 return (this._time / baselineEntry._time - 1) * 100;
1462 }
Ben Murdochc5610432016-08-08 18:44:38 +01001463 get timePercentVariancePercent() {
1464 // Get the absolute values for the percentages
1465 return this.timeVariance / this.page.total._time * 100;
1466 }
1467 getTimeImpact(showDiff) {
1468 return this.page.version.getTotalTime(this.name, showDiff);
1469 }
1470 getTimeImpactVariancePercent(showDiff) {
1471 return this.page.version.getTotalTimeVariancePercent(this.name, showDiff);
1472 }
1473 getTimePercentImpact(showDiff) {
1474 return this.page.version.getTotalTimePercent(this.name, showDiff);
1475 }
1476 getCountImpact(showDiff) {
1477 return this.page.version.getTotalCount(this.name, showDiff);
1478 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001479 getAverageTimeImpact(showDiff) {
1480 return this.page.version.getAverageTimeImpact(this.name, showDiff);
1481 }
Ben Murdochc5610432016-08-08 18:44:38 +01001482 getPagesByPercentImpact() {
1483 return this.page.version.getPagesByPercentImpact(this.name);
1484 }
1485 get isGroup() {
1486 return false
1487 }
1488 get timeVariance() {
1489 return this._timeVariance
1490 }
1491 get timeVariancePercent() {
1492 return this._timeVariancePercent
1493 }
1494 }
1495 Entry.fromJSON = function(position, data) {
1496 return new Entry(position, ...data);
1497 }
1498
1499
1500 class GroupedEntry extends Entry {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001501 constructor(name, regexp, color) {
Ben Murdochc5610432016-08-08 18:44:38 +01001502 super(0, 'Group-' + name, 0, 0, 0, 0, 0, 0);
1503 this.regexp = regexp;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001504 this.color = color;
Ben Murdochc5610432016-08-08 18:44:38 +01001505 this.entries = [];
1506 }
1507 add(entry) {
1508 if (!entry.name.match(this.regexp)) return false;
1509 this._time += entry.time;
1510 this._count += entry.count;
1511 // TODO: sum up variance
1512 this.entries.push(entry);
1513 entry.parent = this;
1514 return true;
1515 }
1516 forEach(fun) {
1517 if (baselineVersion === undefined) {
1518 this.entries.forEach(fun);
1519 return;
1520 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001521 // If we have a baslineVersion to compare against show also all entries
1522 // from the other group.
Ben Murdochc5610432016-08-08 18:44:38 +01001523 var tmpEntries = baselineVersion.getEntry(this)
1524 .entries.filter((entry) => {
1525 return this.page.get(entry.name) == undefined
1526 });
1527
1528 // The compared entries are sorted by absolute impact.
1529 tmpEntries = tmpEntries.map((entry) => {
1530 var tmpEntry = new Entry(0, entry.name, 0, 0, 0, 0, 0, 0);
1531 tmpEntry.page = this.page;
1532 return tmpEntry;
1533 });
1534 tmpEntries = tmpEntries.concat(this.entries);
1535 tmpEntries.sort((a, b) => {
1536 return a.time - b.time
1537 });
1538 tmpEntries.forEach(fun);
1539 }
1540 sort() {
1541 this.entries.sort((a, b) => {
1542 return b.time - a.time;
1543 });
1544 }
1545 cssClass() {
1546 if (this.page.total == this) return 'total';
1547 return '';
1548 }
1549 get isGroup() {
1550 return true
1551 }
1552 getVarianceForProperty(property) {
1553 var sum = 0;
1554 this.entries.forEach((entry) => {
1555 sum += entry[property + 'Variance'] * entry[property +
1556 'Variance'];
1557 });
1558 return Math.sqrt(sum);
1559 }
1560 get timeVariancePercent() {
1561 if (this._time == 0) return 0;
1562 return this.getVarianceForProperty('time') / this._time * 100
1563 }
1564 get timeVariance() {
1565 return this.getVarianceForProperty('time')
1566 }
1567 }
1568
1569 class UnclassifiedEntry extends GroupedEntry {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001570 constructor(page, color) {
1571 super('Unclassified', undefined, color);
Ben Murdochc5610432016-08-08 18:44:38 +01001572 this.page = page;
1573 this._time = undefined;
1574 this._count = undefined;
1575 }
1576 add(entry) {
1577 this.entries.push(entry);
1578 entry.parent = this;
1579 return true;
1580 }
1581 forEachPageGroup(fun) {
1582 this.page.forEachGroup((group) => {
1583 if (group == this) return;
1584 if (group == this.page.total) return;
1585 fun(group);
1586 });
1587 }
1588 get time() {
1589 if (this._time === undefined) {
1590 this._time = this.page.total._time;
1591 this.forEachPageGroup((group) => {
1592 this._time -= group._time;
1593 });
1594 }
1595 return this.getCompareWithBaseline(this._time, '_time');
1596 }
1597 get count() {
1598 if (this._count === undefined) {
1599 this._count = this.page.total._count;
1600 this.forEachPageGroup((group) => {
1601 this._count -= group._count;
1602 });
1603 }
1604 return this.getCompareWithBaseline(this._count, '_count');
1605 }
1606 }
1607 </script>
1608</head>
1609
Ben Murdoch61f157c2016-09-16 13:49:30 +01001610<body id="body" onmousemove="handleUpdatePopover(event)" onload="handleBodyLoad()" class="noDiff">
Ben Murdochc5610432016-08-08 18:44:38 +01001611 <h1>Runtime Stats Komparator</h1>
1612
1613 <div id="results">
1614 <div class="inline">
1615 <h2>Data</h2>
1616 <form name="fileForm">
1617 <p>
1618 <input id="uploadInput" type="file" name="files" onchange="handleLoadFile();" accept=".json">
1619 </p>
1620 </form>
1621 </div>
1622
1623 <div class="inline hidden">
1624 <h2>Result</h2>
1625 <div class="compareSelector inline">
1626 Compare against:&nbsp;<select id="baseline" onchange="handleSelectBaseline(this, event)"></select><br/>
1627 <span style="color: #060">Green</span> the selected version above performs
1628 better on this measurement.
1629 </div>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001630 </div>
1631
1632 <div id="versionSelector" class="inline toggleContentVisibility">
1633 <h2>Version Selector</h2>
1634 <div class="content hidden">
Ben Murdochc5610432016-08-08 18:44:38 +01001635 <ul></ul>
1636 </div>
1637 </div>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001638
1639 <div id="pageSelector" class="inline toggleContentVisibility">
1640 <h2>Page Selector</h2>
1641 <div class="content hidden">
1642 <ul></ul>
1643 </div>
1644 </div>
1645
Ben Murdochc5610432016-08-08 18:44:38 +01001646 <div id="view">
1647 </div>
1648
1649 <div id="detailView" class="hidden">
Ben Murdoch61f157c2016-09-16 13:49:30 +01001650 <div class="versionDetail inline toggleContentVisibility">
1651 <h3><span></span></h3>
1652 <div class="content">
1653 <table class="versionDetailTable" onclick="handleSelectDetailRow(this, event);">
1654 <thead>
1655 <tr>
1656 <th class="version">Version&nbsp;</th>
1657 <th class="position">Pos.&nbsp;</th>
1658 <th class="value time">Time▴&nbsp;</th>
1659 <th class="value time">Percent&nbsp;</th>
1660 <th class="value count">Count&nbsp;</th>
1661 </tr>
1662 </thead>
1663 <tbody></tbody>
1664 </table>
1665 </div>
Ben Murdochc5610432016-08-08 18:44:38 +01001666 </div>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001667 <div class="pageDetail inline toggleContentVisibility">
Ben Murdochc5610432016-08-08 18:44:38 +01001668 <h3>Page Comparison for <span></span></h3>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001669 <div class="content">
1670 <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);">
1671 <thead>
1672 <tr>
1673 <th class="page">Page&nbsp;</th>
1674 <th class="value time">Time&nbsp;</th>
1675 <th class="value time">Percent▾&nbsp;</th>
1676 <th class="value time hideNoDiff">%/Entry&nbsp;</th>
1677 <th class="value count">Count&nbsp;</th>
1678 </tr>
1679 </thead>
1680 <tfoot>
1681 <tr>
1682 <td class="page">Total:</td>
1683 <td class="value time"></td>
1684 <td class="value time"></td>
1685 <td class="value time hideNoDiff"></td>
1686 <td class="value count"></td>
1687 </tr>
1688 </tfoot>
1689 <tbody></tbody>
1690 </table>
1691 </div>
Ben Murdochc5610432016-08-08 18:44:38 +01001692 </div>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001693 <div class="impactView inline toggleContentVisibility">
Ben Murdochc5610432016-08-08 18:44:38 +01001694 <h3>Impact list for <span></span></h3>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001695 <div class="content">
1696 <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);">
1697 <thead>
1698 <tr>
1699 <th class="page">Name&nbsp;</th>
1700 <th class="value time">Time&nbsp;</th>
1701 <th class="value time">Percent▾&nbsp;</th>
1702 <th class="">Top Pages</th>
1703 </tr>
1704 </thead>
1705 <tbody></tbody>
1706 </table>
1707 </div>
Ben Murdochc5610432016-08-08 18:44:38 +01001708 </div>
1709 </div>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001710 <div id="pageVersionGraph" class="graph hidden toggleContentVisibility">
1711 <h3><span></span></h3>
1712 <div class="content"></div>
1713 </div>
1714 <div id="pageGraph" class="graph hidden toggleContentVisibility">
1715 <h3><span></span></h3>
1716 <div class="content"></div>
1717 </div>
1718 <div id="versionGraph" class="graph hidden toggleContentVisibility">
1719 <h3><span></span></h3>
1720 <div class="content"></div>
Ben Murdochc5610432016-08-08 18:44:38 +01001721 </div>
1722
1723 <div id="column" class="column">
1724 <div class="header">
1725 <select class="version" onchange="handleSelectVersion(this, event);"></select>
1726 <select class="pageVersion" onchange="handleSelectPage(this, event);"></select>
1727 </div>
1728 <table class="list" onclick="handleSelectRow(this, event);">
1729 <thead>
1730 <tr>
1731 <th class="position">Pos.&nbsp;</th>
1732 <th class="name">Name&nbsp;</th>
1733 <th class="value time">Time&nbsp;</th>
1734 <th class="value time">Percent&nbsp;</th>
1735 <th class="value count">Count&nbsp;</th>
1736 </tr>
1737 </thead>
1738 <tbody></tbody>
1739 </table>
1740 </div>
1741 </div>
1742
1743 <div class="inline">
1744 <h2>Usage</h2>
1745 <ol>
1746 <li>Install scipy, e.g. <code>sudo aptitude install python-scipy</code>
1747 <li>Build chrome with the <a href="https://codereview.chromium.org/1923893002">extended runtime callstats</a>.</li>
1748 <li>Run <code>callstats.py</code> with a web-page-replay archive:
1749 <pre>$V8_DIR/tools/callstats.py run \
1750 --replay-bin=$CHROME_SRC/third_party/webpagereplay/replay.py \
1751 --replay-wpr=$INPUT_DIR/top25.wpr \
1752 --js-flags="" \
1753 --with-chrome=$CHROME_SRC/out/Release/chrome \
1754 --sites-file=$INPUT_DIR/top25.json</pre>
1755 </li>
1756 <li>Move results file to a subdirectory: <code>mkdir $VERSION_DIR; mv *.txt $VERSION_DIR</code></li>
1757 <li>Repeat from step 1 with a different configuration (e.g. <code>--js-flags="--nolazy"</code>).</li>
1758 <li>Create the final results file: <code>./callstats.py json $VERSION_DIR1 $VERSION_DIR2 > result.json</code></li>
1759 <li>Use <code>results.json</code> on this site.</code>
1760 </ol>
1761 </div>
1762
1763 <div id="popover">
1764 <div class="popoverArrow"></div>
1765 <table>
1766 <tr>
1767 <td class="name" colspan="6"></td>
1768 </tr>
1769 <tr>
1770 <td>Page:</td>
1771 <td class="page name" colspan="6"></td>
1772 </tr>
1773 <tr>
1774 <td>Version:</td>
1775 <td class="version name" colspan="3"></td>
1776 <td class="compare version name" colspan="3"></td>
1777 </tr>
1778 <tr>
1779 <td>Time:</td>
1780 <td class="time"></td><td>±</td><td class="timeVariance"></td>
1781 <td class="compare time"></td><td class="compare"> ± </td><td class="compare timeVariance"></td>
1782 </tr>
1783 <tr>
1784 <td>Percent:</td>
1785 <td class="percent"></td><td>±</td><td class="percentVariance"></td>
1786 <td class="compare percent"></td><td class="compare"> ± </td><td class="compare percentVariance"></td>
1787 </tr>
1788 <tr>
Ben Murdoch61f157c2016-09-16 13:49:30 +01001789 <td>Percent per Entry:</td>
1790 <td class="percentPerEntry"></td><td colspan=2></td>
1791 <td class="compare percentPerEntry"></td><td colspan=2></td>
1792 </tr>
1793 <tr>
Ben Murdochc5610432016-08-08 18:44:38 +01001794 <td>Count:</td>
1795 <td class="count"></td><td>±</td><td class="countVariance"></td>
1796 <td class="compare count"></td><td class="compare"> ± </td><td class="compare countVariance"></td>
1797 </tr>
1798 <tr>
1799 <td>Overall Impact:</td>
1800 <td class="timeImpact"></td><td>±</td><td class="timePercentImpact"></td>
1801 <td class="compare timeImpact"></td><td class="compare"> ± </td><td class="compare timePercentImpact"></td>
1802 </tr>
1803 </table>
1804 </div>
Ben Murdochc5610432016-08-08 18:44:38 +01001805</body>
Ben Murdochc5610432016-08-08 18:44:38 +01001806</html>