Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: tools/callstats.html

Issue 1947413004: [tools] Add callstats.html to analize --runtime-call-stats output (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/ic-explorer.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 <html>
2 <!--
3 Copyright 2016 the V8 project authors. All rights reserved. Use of this source
4 code 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 }
60
61 .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
113 .list .position {
114 text-align: right;
115 display: none;
116 }
117
118 .list div.toggle {
119 cursor: pointer;
120 }
121
122 #column_0 .position {
123 display: table-cell;
124 }
125
126 #column_0 .name {
127 display: table-cell;
128 }
129
130 .list .name {
131 display: none;
132 white-space: nowrap;
133 }
134
135 .value {
136 text-align: right;
137 }
138
139 .selectedVersion {
140 font-weight: bold;
141 }
142
143 #baseline {
144 width: auto;
145 }
146
147 .compareSelector {
148 padding-bottom: 20px;
149 }
150
151 .pageDetailTable tbody {
152 cursor: pointer
153 }
154
155 #popover {
156 position: absolute;
157 transform: translateY(-50%) translateX(40px);
158 box-shadow: -2px 10px 44px -10px #000;
159 border-radius: 5px;
160 z-index: 1;
161 background-color: #FFF;
162 display: none;
163 }
164
165 #popover table {
166 position: relative;
167 z-index: 1;
168 text-align: right;
169 }
170
171 .popoverArrow {
172 background-color: #FFF;
173 position: absolute;
174 width: 30px;
175 height: 30px;
176 transform: translateY(-50%)rotate(45deg);
177 top: 50%;
178 left: -10px;
179 z-index: 0;
180 }
181
182 #popover .name {
183 padding: 5px;
184 font-weight: bold;
185 text-align: center;
186 }
187
188 #popover table .compare {
189 display: none
190 }
191
192 #popover table.compare .compare {
193 display: table-cell;
194 }
195 </style>
196 <script>
197 "use strict"
198
199 // Did anybody say monkeypatching?
200 if (!NodeList.prototype.forEach) {
201 NodeList.prototype.forEach = function(func) {
202 for (var i = 0; i < this.length; i++) {
203 func(this[i]);
204 }
205 }
206 }
207
208 var versions;
209 var selectedPage;
210 var baselineVersion;
211 var selectedEntry;
212
213 function initialize() {
214 var original = $("column");
215 for (var i = 0; i < versions.length || i < 2; i++) {
216 // add column
217 var column = original.cloneNode(true);
218 column.id = "column_" + i;
219 // Fill in all versions
220 var select = column.querySelector(".version");
221 select.id = "selectVersion_" + i;
222 // add all select options
223 versions.forEach((version) => {
224 var option = document.createElement("option");
225 option.textContent = version.name;
226 option.version = version;
227 select.appendChild(option);
228 });
229 // Fill in all page versions
230 select = column.querySelector(".pageVersion");
231 select.id = "select_" + i;
232 // add all select options
233 versions.forEach((version) => {
234 var optgroup = document.createElement("optgroup");
235 optgroup.label = version.name;
236 optgroup.version = version;
237 version.pages.forEach((page) => {
238 var option = document.createElement("option");
239 option.textContent = page.name;
240 option.page = page;
241 optgroup.appendChild(option);
242 });
243 select.appendChild(optgroup);
244 });
245 $("view").appendChild(column);
246 }
247 var select = $('baseline');
248 removeAllChildren(select);
249 select.appendChild(document.createElement('option'));
250 versions.forEach((version) => {
251 var option = document.createElement("option");
252 option.textContent = version.name;
253 option.version = version;
254 select.appendChild(option);
255 });
256 $('results').querySelectorAll('#results > .hidden').forEach((node) => {
257 toggleCssClass(node, 'hidden', false);
258 });
259 }
260
261 function showPage(firstPage) {
262 selectedPage = firstPage;
263 selectedPage.sort();
264 showPageInColumn(firstPage, 0);
265 // Show the other versions of this page in the following columns.
266 var pageVersions = versions.pageVersions(firstPage.name);
267 var index = 1;
268 pageVersions.forEach((page) => {
269 if (page !== firstPage) {
270 showPageInColumn(page, index);
271 index++;
272 }
273 });
274 showImpactList(selectedPage);
275 }
276
277 function showPageInColumn(page, columnIndex) {
278 page.sort();
279 var showDiff = (baselineVersion === undefined && columnIndex !== 0) ||
280 (baselineVersion !== undefined && page.version !== baselineVersion);
281 var diffStatus = (td, a, b) => {};
282 if (showDiff) {
283 if (baselineVersion !== undefined) {
284 diffStatus = (td, a, b) => {
285 if (a == 0) return;
286 td.style.color = a < 0 ? '#FF0000' : '#00BB00';
287 };
288 } else {
289 diffStatus = (td, a, b) => {
290 if (a == b) return;
291 var color;
292 var ratio = a / b;
293 if (ratio > 1) {
294 ratio = Math.min(Math.round((ratio - 1) * 255 * 10), 200);
295 color = '#' + ratio.toString(16) + "0000";
296 } else {
297 ratio = Math.min(Math.round((1 - ratio) * 255 * 10), 200);
298 color = '#00' + ratio.toString(16) + "00";
299 }
300 td.style.color = color;
301 }
302 }
303 }
304
305 var column = $('column_' + columnIndex);
306 var select = $('select_' + columnIndex);
307 // Find the matching option
308 selectOption(select, (i, option) => {
309 return option.page == page
310 });
311 var table = column.querySelector("table");
312 var oldTbody = table.querySelector('tbody');
313 var tbody = document.createElement('tbody');
314 var referencePage = selectedPage;
315 page.forEachSorted(selectedPage, (parentEntry, entry, referenceEntry) => {
316 // Filter out entries that do not exist in the first column for the defa ult
nickie 2016/05/06 12:40:48 Comment line too long. Move "default" to next lin
317 // view.
318 if (baselineVersion === undefined && referenceEntry &&
319 referenceEntry.time == 0) {
320 return;
321 }
322 var tr = document.createElement('tr');
323 tbody.appendChild(tr);
324 tr.entry = entry;
325 tr.parentEntry = parentEntry;
326 if (!parentEntry) {
327 tr.className = 'parent'
328 } else {
329 tr.className = 'child'
330 }
331 // Don't show entries that do not exist on the current page or if we com pare
nickie 2016/05/06 12:40:48 Same. Move "compare" to next line?
332 // against the current page
333 if (entry !== undefined && page.version !== baselineVersion) {
334 // If we show a diff, use the baselineVersion as the referenceEntry
335 if (baselineVersion !== undefined) {
336 var baselineEntry = baselineVersion.getEntry(entry);
337 if (baselineEntry !== undefined) referenceEntry = baselineEntry
338 }
339 if (!parentEntry) {
340 var node = td(tr, '<div class="toggle">►</div>', 'position');
341 node.firstChild.addEventListener('click', handleToggleGroup);
342 } else {
343 td(tr, entry.position == 0 ? '' : entry.position, 'position');
344 }
345 td(tr, entry.name, 'name ' + entry.cssClass());
346 diffStatus(
347 td(tr, ms(entry.time), 'value time'),
348 entry.time, referenceEntry.time);
349 diffStatus(
350 td(tr, percent(entry.timePercent), 'value time'),
351 entry.time, referenceEntry.time);
352 diffStatus(
353 td(tr, count(entry.count), 'value count'),
354 entry.count, referenceEntry.count);
355 } else if (baselineVersion !== undefined && referenceEntry && page.versi on !==
nickie 2016/05/06 12:40:48 Bad formatting. Break after last "&&"?
356 baselineVersion) {
357 // Show comparison of entry that does not exist on the current page.
358 tr.entry = referenceEntry;
359 td(tr, '-', 'position');
360 td(tr, referenceEntry.name, 'name');
361 diffStatus(
362 td(tr, ms(referenceEntry.time), 'value time'),
363 referenceEntry.time, 0);
364 diffStatus(
365 td(tr, percent(referenceEntry.timePercent), 'value time'),
366 referenceEntry.timePercent, 0);
367 diffStatus(
368 td(tr, count(referenceEntry.count), 'value count'),
369 referenceEntry.count, 0);
370 } else {
371 // Display empty entry / baseline entry
372 if (entry !== undefined) {
373 if (!parentEntry) {
374 var node = td(tr, '<div class="toggle">►</div>', 'position');
375 node.firstChild.addEventListener('click', handleToggleGroup);
376 } else {
377 td(tr, entry.position == 0 ? '' : entry.position, 'position');
378 }
379 td(tr, entry.name, 'name');
380 } else {
381 td(tr, '-', 'position');
382 td(tr, '-', 'name');
383 }
384 td(tr, '-', 'value time');
385 td(tr, '-', 'value time');
386 td(tr, '-', 'value count');
387 }
388 });
389 table.replaceChild(tbody, oldTbody);
390 var versionSelect = column.querySelector('select.version');
391 selectOption(versionSelect, (index, option) => {
392 return option.version == page.version
393 });
394 }
395
396 function selectEntry(entry, updateSelectedPage) {
397 if (updateSelectedPage) {
398 entry = selectedPage.version.getEntry(entry);
399 }
400 var rowIndex;
401 var needsPageSwitch = updateSelectedPage && entry.page != selectedPage;
402 // If clicked in the detail row change the first column to that page.
403 if (needsPageSwitch) showPage(entry.page);
404 var childNodes = $('column_0').querySelector('.list tbody').childNodes;
405 for (var i = 0; i < childNodes.length; i++) {
406 if (childNodes[i].entry.name == entry.name) {
407 rowIndex = i;
408 break;
409 }
410 }
411 var firstEntry = childNodes[rowIndex].entry;
412 if (rowIndex) {
413 if (firstEntry.parent) showGroup(firstEntry.parent);
414 }
415 // Deselect all
416 $('view').querySelectorAll('.list tbody tr').forEach((tr) => {
417 toggleCssClass(tr, 'selected', false);
418 });
419 // Select the entry row
420 $('view').querySelectorAll("tbody").forEach((body) => {
421 var row = body.childNodes[rowIndex];
422 if (!row) return;
423 toggleCssClass(row, 'selected', row.entry && row.entry.name ==
424 firstEntry.name);
425 });
426 if (updateSelectedPage) {
427 entry = selectedEntry.page.version.getEntry(entry);
428 }
429 selectedEntry = entry;
430 showEntryDetail(entry);
431 }
432
433 function showEntryDetail(entry) {
434 var table, tbody, entries;
435 table = $('detailView').querySelector('.versionDetailTable');
436 tbody = document.createElement('tbody');
437 if (entry !== undefined) {
438 $('detailView').querySelector('.versionDetail h3 span').innerHTML =
439 entry.name;
440 entries = versions.pageVersions(entry.page.name).map(
441 (page) => {
442 return page.get(entry.name)
443 });
444 entries.sort((a, b) => {
445 return a.time - b.time
446 });
447 entries.forEach((pageEntry) => {
448 if (pageEntry === undefined) return;
449 var tr = document.createElement('tr');
450 if (pageEntry == entry) tr.className += 'selected';
451 tr.entry = pageEntry;
452 td(tr, pageEntry.page.version.name, 'version');
453 td(tr, pageEntry.position, 'value position');
454 td(tr, ms(pageEntry.time), 'value time');
455 td(tr, percent(pageEntry.timePercent), 'value time');
456 td(tr, count(pageEntry.count), 'value count');
457 tbody.appendChild(tr);
458 });
459 }
460 table.replaceChild(tbody, table.querySelector('tbody'));
461
462 table = $('detailView').querySelector('.pageDetailTable');
463 tbody = document.createElement('tbody');
464 if (entry !== undefined) {
465 var version = entry.page.version;
466 $('detailView').querySelector('.pageDetail h3 span').innerHTML =
467 version.name;
468 entries = version.pages.map(
469 (page) => {
470 return page.get(entry.name)
471 });
472 entries.sort((a, b) => {
473 return b.timePercent - a.timePercent
474 });
475 entries.forEach((pageEntry) => {
476 if (pageEntry === undefined) return;
477 var tr = document.createElement('tr');
478 if (pageEntry === entry) tr.className += 'selected';
479 tr.entry = pageEntry;
480 td(tr, pageEntry.page.name, 'name');
481 td(tr, pageEntry.position, 'value position');
482 td(tr, ms(pageEntry.time), 'value time');
483 td(tr, percent(pageEntry.timePercent), 'value time');
484 td(tr, count(pageEntry.count), 'value count');
485 tbody.appendChild(tr);
486 });
487 // show the total for all pages
488 var tds = table.querySelectorAll('tfoot td');
489 tds[2].innerHTML = ms(entry.getTimeImpact());
490 // Only show the percentage total if we are in diff mode:
491 if (baselineVersion !== undefined) {
492 tds[3].innerHTML = percent(entry.getTimePercentImpact());
493 } else {
494 tds[3].innerHTML = ''
495 }
496 tds[4].innerHTML = count(entry.getCountImpact());
497 }
498 table.replaceChild(tbody, table.querySelector('tbody'));
499 showImpactList(entry.page);
500 }
501
502 function showImpactList(page) {
503 var impactView = $('detailView').querySelector('.impactView');
504 impactView.querySelector('h3 span').innerHTML = page.version.name;
505
506 var table = impactView.querySelector('table');
507 var tbody = document.createElement('tbody');
508 var version = page.version;
509 var entries = version.allEntries();
510 if (selectedEntry !== undefined && selectedEntry.isGroup) {
511 impactView.querySelector('h3 span').innerHTML += " " + selectedEntry.nam e;
nickie 2016/05/06 12:40:48 Bad formatting. Break after "+="?
512 entries = entries.filter((entry) => {
513 return entry.name == selectedEntry.name ||
nickie 2016/05/06 12:40:48 "(entry) => { return ... }" can be written as "ent
514 (entry.parent && entry.parent.name == selectedEntry.name)
515 });
516 }
517 entries.sort((a, b) => {
518 return b.getTimePercentImpact() - a.getTimePercentImpact();
519 });
520 entries.forEach((entry) => {
521 var tr = document.createElement('tr');
522 tr.entry = entry;
523 td(tr, entry.name, 'name');
524 td(tr, ms(entry.getTimeImpact()), 'value time');
525 td(tr, percent(entry.getTimePercentImpact()), 'value time');
526 var topPages = entry.getPagesByPercentImpact().slice(0, 2)
527 .map((each) => {
528 return each.name + ' (' + percent(each.getEntry(entry).timePercent) +
nickie 2016/05/06 12:40:48 Bad formatting. You can skip the braces and the "
529 ')'
530 });
531 td(tr, topPages.join(', '), 'name');
532 tbody.appendChild(tr);
533 });
534 table.replaceChild(tbody, table.querySelector('tbody'));
535 }
536
537 function showGroup(entry) {
538 toggleGroup(entry, true);
539 }
540
541 function toggleGroup(group, show) {
542 $('view').querySelectorAll(".child").forEach((tr) => {
543 var entry = tr.parentEntry;
544 if (!entry) return;
545 if (entry.name !== group.name) return;
546 toggleCssClass(tr, 'visible', show);
547 });
548 }
549
550 function showPopover(entry) {
551 var popover = $('popover');
552 popover.querySelector('td.name').innerHTML = entry.name;
553 popover.querySelector('td.page').innerHTML = entry.page.name;
554 setPopoverDetail(popover, entry, '');
555 popover.querySelector('table').className = "";
556 if (baselineVersion !== undefined) {
557 entry = baselineVersion.getEntry(entry);
558 if (entry === undefined) return;
559 setPopoverDetail(popover, entry, '.compare ');
560 popover.querySelector('table').className = "compare";
561 }
562 }
563
564 function setPopoverDetail(popover, entry, prefix) {
565 popover.querySelector(prefix + '.version').innerHTML = entry.page.version
566 .name;
567 popover.querySelector(prefix + '.time').innerHTML = ms(entry._time);
568 popover.querySelector(prefix + '.timeVariance').innerHTML = percent(entry
569 .timeVariancePercent);
570 popover.querySelector(prefix + '.percent').innerHTML = percent(entry.timeP ercent);
nickie 2016/05/06 12:40:48 Bad formatting. Break after "="?
571 popover.querySelector(prefix + '.percentVariance').innerHTML = percent(
572 entry.timePercentVariancePercent);
573 popover.querySelector(prefix + '.count').innerHTML = count(entry._count);
574 popover.querySelector(prefix + '.countVariance').innerHTML = percent(
575 entry.timeVariancePercent);
576 popover.querySelector(prefix + '.timeImpact').innerHTML = ms(entry.getTime Impact());
nickie 2016/05/06 12:40:48 Bad formatting. Break after "="?
577 popover.querySelector(prefix + '.timePercentImpact').innerHTML = percent(
578 entry.getTimePercentImpact());
579 }
580
581 // ========================================================================= ==
nickie 2016/05/06 12:40:48 Bad formatting. Fewer "="?
582 // Helpers
583 function $(id) {
584 return document.getElementById(id)
585 }
586
587 function removeAllChildren(node) {
588 while (node.firstChild) {
589 node.removeChild(node.firstChild);
590 }
591 }
592
593 function selectOption(select, match) {
594 var options = select.options;
595 for (var i = 0; i < options.length; i++) {
596 if (match(i, options[i])) {
597 select.selectedIndex = i;
598 return;
599 }
600 }
601 }
602
603 function td(tr, content, className) {
604 var td = document.createElement("td");
605 td.innerHTML = content;
606 td.className = className
607 tr.appendChild(td);
608 return td
609 }
610
611 function nodeIndex(node) {
612 var children = node.parentNode.childNodes,
613 i = 0;
614 for (; i < children.length; i++) {
615 if (children[i] == node) {
616 return i;
617 }
618 }
619 return -1;
620 }
621
622 function toggleCssClass(node, cssClass, toggleState) {
623 var index = -1;
624 var classes;
625 if (node.className != undefined) {
626 classes = node.className.split(' ');
627 index = classes.indexOf(cssClass);
628 }
629 if (index == -1) {
630 if (toggleState === false) return;
631 node.className += ' ' + cssClass;
632 return;
633 }
634 if (toggleState === true) return;
635 classes.splice(index, 1);
636 node.className = classes.join(' ');
637 }
638
639 function diffSign(value) {
640 if (value <= 0) return '';
641 if (baselineVersion == undefined) return '';
642 return '+';
643 }
644
645 function ms(time) {
646 return diffSign(time) + time.toFixed(1) + 'ms';
647 }
648
649 function count(time) {
650 return diffSign(time) + time.toFixed(0) + '#';
651 }
652
653 function percent(time) {
654 return diffSign(time) + time.toFixed(1) + '%';
655 }
656 // ========================================================================= ==
nickie 2016/05/06 12:40:48 Bad formatting. Fewer "="? Also, insert one blan
657 // EventHandlers
658 function handleLoadFile() {
659 var files = document.getElementById("uploadInput").files;
660 var file = files[0];
661 var reader = new FileReader();
662
663 reader.onload = function(evt) {
664 versions = Versions.fromJSON(JSON.parse(this.result));
665 initialize()
666 showPage(versions.versions[0].pages[0]);
667 }
668 reader.readAsText(file);
669 }
670
671 function handleToggleGroup(event) {
672 var group = event.target.parentNode.parentNode.entry;
673 toggleGroup(selectedPage.get(group.name));
674 }
675
676 function handleSelectPage(select, event) {
677 var option = select.options[select.selectedIndex];
678 if (select.id == "select_0") {
679 showPage(option.page);
680 } else {
681 var columnIndex = select.id.split('_')[1];
682 showPageInColumn(option.page, columnIndex);
683 }
684 }
685
686 function handleSelectVersion(select, event) {
687 var option = select.options[select.selectedIndex];
688 var version = option.version;
689 if (select.id == "selectVersion_0") {
690 var page = version.get(selectedPage.name);
691 showPage(page);
692 } else {
693 var columnIndex = select.id.split('_')[1];
694 var pageSelect = $('select_' + columnIndex);
695 var page = pageSelect.options[select.selectedIndex].page;
696 page = version.get(page.name);
697 showPageInColumn(page, columnIndex);
698 }
699 }
700
701 function handleSelectDetailRow(table, event) {
702 if (event.target.tagName != 'TD') return;
703 var tr = event.target.parentNode;
704 if (tr.tagName != 'TR') return;
705 if (tr.entry === undefined) return;
706 selectEntry(tr.entry, true);
707 }
708
709 function handleSelectRow(table, event, fromDetail) {
710 if (event.target.tagName != 'TD') return;
711 var tr = event.target.parentNode;
712 if (tr.tagName != 'TR') return;
713 if (tr.entry === undefined) return;
714 selectEntry(tr.entry, false);
715 }
716
717 function handleSelectBaseline(select, event) {
718 var option = select.options[select.selectedIndex];
719 baselineVersion = option.version
720 showPage(selectedPage);
721 selectEntry(selectedEntry, true);
722 }
723
724 function handleUpdatePopover(event) {
725 var popover = $('popover');
726 popover.style.left = event.pageX + 'px';
727 popover.style.top = event.pageY + 'px';
728 popover.style.display = event.shiftKey ? 'block' : 'none';
729 var target = event.target;
730 while (target.entry === undefined) {
731 target = target.parentNode;
732 if (!target) return;
733 }
734 showPopover(target.entry);
735 }
736
737 // ========================================================================= ==
nickie 2016/05/06 12:40:48 Bad formatting. Fewer "="?
738
739 class Versions {
740 constructor() {
741 this.versions = [];
742 }
743 add(version) {
744 this.versions.push(version)
745 }
746 pageVersions(name) {
747 var result = [];
748 this.versions.forEach((version) => {
749 var page = version.get(name);
750 if (page !== undefined) result.push(page);
751 });
752 return result;
753 }
754 get length() {
755 return this.versions.length
756 }
757 get(index) {
758 return this.versions[index]
759 };
760 forEach(f) {
761 this.versions.forEach(f);
762 }
763 sort() {
764 this.versions.sort((a, b) => {
765 if (a.name > b.name) return 1;
766 if (a.name < b.name) return -1;
767 return 0
768 })
769 }
770 }
771 Versions.fromJSON = function(json) {
772 var versions = new Versions();
773 for (var version in json) {
774 versions.add(Version.fromJSON(version, json[version]));
775 }
776 versions.sort();
777 return versions;
778 }
779
780 class Version {
781 constructor(name) {
782 this.name = name;
783 this.pages = []
784 }
785 add(page) {
786 this.pages.push(page);
787 }
788 indexOf(name) {
789 for (var i = 0; i < this.pages.length; i++) {
790 if (this.pages[i].name == name) return i;
791 }
792 return -1;
793 }
794 get(name) {
795 var index = this.indexOf(name);
796 if (0 <= index) return this.pages[index];
797 return undefined
798 }
799 get length() {
800 return this.versions.length
801 }
802 getEntry(entry) {
803 if (entry === undefined) return undefined;
804 var page = this.get(entry.page.name);
805 if (page === undefined) return undefined;
806 return page.get(entry.name);
807 }
808 forEachEntry(fun) {
809 this.pages.forEach((page) => {
810 page.forEach(fun);
811 });
812 }
813 allEntries() {
814 var map = new Map();
815 this.forEachEntry((group, entry) => {
816 if (!map.has(entry.name)) map.set(entry.name, entry);
817 });
818 return Array.from(map.values());
819 }
820 getTotalValue(name, property) {
821 if (name === undefined) name = this.pages[0].total.name;
822 var sum = 0;
823 this.pages.forEach((page) => {
824 var entry = page.get(name);
825 if (entry !== undefined) sum += entry[property];
826 });
827 return sum;
828 }
829 getTotalTime(name) {
830 return this.getTotalValue(name, 'time');
831 }
832 getTotalTimePercent(name) {
833 return this.getTotalValue(name, 'timePercent');
834 }
835 getTotalCount(name) {
836 return this.getTotalValue(name, 'count');
837 }
838 getPagesByPercentImpact(name) {
839 var sortedPages =
840 this.pages.filter((each) => {
841 return each.get(name) !== undefined
842 });
843 sortedPages.sort((a, b) => {
844 return b.get(name).timePercent - a.get(name).timePercent;
845 });
846 return sortedPages;
847 }
848 }
849 Version.fromJSON = function(name, data) {
850 var version = new Version(name);
851 for (var page in data) {
852 version.add(Page.fromJSON(version, page, data[page]));
853 }
854 return version;
855 }
856
857
858 class Page {
859 constructor(version, name) {
860 this.name = name;
861 this.total = new GroupedEntry('Total', /.*Total.*/);
862 this.unclassified = new UnclassifiedEntry(this)
863 this.groups = [
864 this.total,
865 new GroupedEntry('IC', /.*IC.*/),
866 new GroupedEntry('Optimize',
867 /StackGuard|.*Optimize.*|.*Deoptimize.*|Recompile.*/),
868 new GroupedEntry('Compile', /.*Compile.*|Parse.*/),
869 new GroupedEntry('Callback', /.*Callback$/),
870 new GroupedEntry('API', /.*API.*/),
871 new GroupedEntry('GC', /GC|AllocateInTargetSpace/),
872 new GroupedEntry('JavaScript', /JS_Execution/),
873 this.unclassified
874 ];
875 this.entryDict = new Map();
876 this.groups.forEach((entry) => {
877 entry.page = this;
878 this.entryDict.set(entry.name, entry);
879 });
880 this.version = version;
881 }
882 add(entry) {
883 entry.page = this;
884 this.entryDict.set(entry.name, entry);
885 var added = false;
886 this.groups.forEach((group) => {
887 if (!added) added = group.add(entry);
888 });
889 if (added) return;
890 this.unclassified.push(entry);
891 }
892 get(name) {
893 return this.entryDict.get(name)
894 }
895 getEntry(entry) {
896 if (entry === undefined) return undefined;
897 return this.get(entry.name);
898 }
899 get length() {
900 return this.versions.length
901 }
902 forEachSorted(referencePage, func) {
903 // Iterate over all the entries in the order they appear on the referenc e page.
nickie 2016/05/06 12:40:48 Bad formatting. Move two words to next line?
904 referencePage.forEach((parent, referenceEntry) => {
905 var entry;
906 if (parent) parent = this.entryDict.get(parent.name);
907 if (referenceEntry) entry = this.entryDict.get(referenceEntry.name);
908 func(parent, entry, referenceEntry);
909 });
910 }
911 forEach(fun) {
912 this.forEachGroup((group) => {
913 fun(undefined, group);
914 group.forEach((entry) => {
915 fun(group, entry)
916 });
917 });
918 }
919 forEachGroup(fun) {
920 this.groups.forEach(fun)
921 }
922 sort() {
923 this.groups.sort((a, b) => {
924 return b.time - a.time;
925 });
926 this.groups.forEach((group) => {
927 group.sort()
928 });
929 }
930 }
931 Page.fromJSON = function(version, name, data) {
932 var page = new Page(version, name);
933 for (var i = 0; i < data.length; i++) {
934 page.add(Entry.fromJSON(i, data[data.length - i - 1]));
935 }
936 page.sort();
937 return page
938 }
939
940
941 class Entry {
942 constructor(position, name, time, timeVariance, timeVariancePercent,
943 count,
944 countVariance, countVariancePercent) {
945 this.position = position;
946 this.name = name;
947 this._time = time;
948 this._timeVariance = timeVariance;
949 this._timeVariancePercent = timeVariancePercent;
950 this._count = count;
951 this.countVariance = countVariance;
952 this.countVariancePercent = countVariancePercent;
953 this.page = undefined;
954 this.parent = undefined;
955 }
956 getCompareWithBaseline(value, property) {
957 if (baselineVersion == undefined) return value;
958 var baselineEntry = baselineVersion.getEntry(this);
959 if (!baselineEntry) return value;
960 if (baselineVersion === this.page.version) return value;
961 return value - baselineEntry[property];
962 }
963 cssClass() {
964 return ''
965 }
966 get time() {
967 return this.getCompareWithBaseline(this._time, '_time');
968 }
969 get count() {
970 return this.getCompareWithBaseline(this._count, '_count');
971 }
972 get timePercent() {
973 var value = this._time / this.page.total._time * 100;
974 if (baselineVersion == undefined) return value;
975 var baselineEntry = baselineVersion.getEntry(this);
976 if (!baselineEntry) return value;
977 return (this._time - baselineEntry._time) / this.page.total._time *
978 100;
979 }
980 get timePercentVariancePercent() {
981 // Get the absolute values for the percentages
982 return this.timeVariance / this.page.total._time * 100;
983 }
984 getTimeImpact() {
985 return this.page.version.getTotalTime(this.name);
986 }
987 getTimePercentImpact() {
988 return this.page.version.getTotalTimePercent(this.name);
989 }
990 getCountImpact() {
991 return this.page.version.getTotalCount(this.name);
992 }
993 getPagesByPercentImpact() {
994 return this.page.version.getPagesByPercentImpact(this.name);
995 }
996 get isGroup() {
997 return false
998 }
999 get timeVariance() {
1000 return this._timeVariance
1001 }
1002 get timeVariancePercent() {
1003 return this._timeVariancePercent
1004 }
1005 }
1006 Entry.fromJSON = function(position, data) {
1007 return new Entry(position, ...data);
1008 }
1009
1010
1011 class GroupedEntry extends Entry {
1012 constructor(name, regexp) {
1013 super(0, 'Group-' + name, 0, 0, 0, 0, 0, 0);
1014 this.regexp = regexp;
1015 this.entries = [];
1016 }
1017 add(entry) {
1018 if (!entry.name.match(this.regexp)) return false;
1019 this._time += entry.time;
1020 this._count += entry.count;
1021 // TODO: sum up variance
1022 this.entries.push(entry);
1023 entry.parent = this;
1024 return true;
1025 }
1026 forEach(fun) {
1027 if (baselineVersion === undefined) {
1028 this.entries.forEach(fun);
1029 return;
1030 }
1031 // If we have a baslineVersion to compare against show also all entries from the
nickie 2016/05/06 12:40:48 Bad formatting. Move two words to next line?
1032 // other group.
1033 var tmpEntries = baselineVersion.getEntry(this)
1034 .entries.filter((entry) => {
1035 return this.page.get(entry.name) == undefined
1036 });
1037
1038 // The compared entries are sorted by absolute impact.
1039 tmpEntries = tmpEntries.map((entry) => {
1040 var tmpEntry = new Entry(0, entry.name, 0, 0, 0, 0, 0, 0);
1041 tmpEntry.page = this.page;
1042 return tmpEntry;
1043 });
1044 tmpEntries = tmpEntries.concat(this.entries);
1045 tmpEntries.sort((a, b) => {
1046 return a.time - b.time
1047 });
1048 tmpEntries.forEach(fun);
1049 }
1050 sort() {
1051 this.entries.sort((a, b) => {
1052 return b.time - a.time;
1053 });
1054 }
1055 cssClass() {
1056 if (this.page.total == this) return 'total';
1057 return '';
1058 }
1059 get isGroup() {
1060 return true
1061 }
1062 getVariancePercentForProperty(property) {
1063 var sum = 0;
1064 this.entries.forEach((entry) => {
1065 sum += entry[property + 'Variance'] * entry[property +
1066 'Variance'];
1067 });
1068 return Math.sqrt(sum) / this['_' + property] * 100;
1069 }
1070 get timeVariancePercent() {
1071 return this.getVariancePercentForProperty('time')
1072 }
1073 get timeVariance() {
1074 return this.getVariancePercentForProperty('timePercent')
1075 }
1076 }
1077
1078 class UnclassifiedEntry extends GroupedEntry {
1079 constructor(page) {
1080 super('Unclassified');
1081 this.page = page;
1082 this._time = undefined;
1083 this._count = undefined;
1084 }
1085 add(entry) {
1086 this.entries.push(entry);
1087 entry.parent = this;
1088 return true;
1089 }
1090 forEachPageGroup(fun) {
1091 this.page.forEachGroup((group) => {
1092 if (group == this) return;
1093 if (group == this.page.total) return;
1094 fun(group);
1095 });
1096 }
1097 get time() {
1098 if (this._time !== undefined) {
1099 return this.getCompareWithBaseline(this._time, '_time');
1100 }
1101 this._time = 0;
1102 var t = this.page.total.time;
1103 this.forEachPageGroup((group) => {
1104 t -= group.time;
1105 });
1106 this._time = Math.round(t);
1107 return this._time;
1108 }
1109 get count() {
1110 if (this._count !== undefined) {
1111 return this.getCompareWithBaseline(this._count, '_count');
1112 }
1113 this._count = 0;
1114 var c = this.page.total.count;
1115 this.forEachPageGroup((group) => {
1116 c -= group.count;
1117 });
1118 this._count = Math.round(c);
1119 return this._count;
1120 }
1121 }
1122 </script>
1123 </head>
1124
1125 <body onmousemove="handleUpdatePopover(event)">
1126 <h1>Runtime Stats Komparator</h1>
1127
1128 <div id="results">
1129 <div class="inline">
1130 <h2>Data</h2>
1131 <form name="fileForm">
1132 <p>
1133 <input id="uploadInput" type="file" name="files" onchange="handleLoadF ile();">
1134 </p>
1135 </form>
1136 </div>
1137 <div class="inline hidden">
1138 <h2>Result</h2>
1139 <div class="compareSelector">
1140 Compare against:&nbsp;<select id="baseline" onchange="handleSelectBaseli ne(this, event)"></select><br/>
1141 <span style="color: #060">Green</span> the selected version above perfor ms
1142 better on this measurement.
1143 </div>
1144 </div>
1145 <div id="view">
1146 </div>
1147
1148 <div id="detailView" class="hidden">
1149 <h2></h2>
1150 <div class="versionDetail inline">
1151 <h3><span></span></h3>
1152 <table class="versionDetailTable" onclick="handleSelectDetailRow(this, e vent);">
1153 <thead>
1154 <tr>
1155 <th class="version">Version&nbsp;</th>
1156 <th class="position">Pos.&nbsp;</th>
1157 <th class="value time">Time▴&nbsp;</th>
1158 <th class="value time">Percent&nbsp;</th>
1159 <th class="value count">Count&nbsp;</th>
1160 </tr>
1161 </thead>
1162 <tbody></tbody>
1163 </table>
1164 </div>
1165 <div class="pageDetail inline">
1166 <h3><span></span></h3>
1167 <table class="pageDetailTable" onclick="handleSelectDetailRow(this, even t);">
1168 <thead>
1169 <tr>
1170 <th class="page">Page&nbsp;</th>
1171 <th class="position">Pos.&nbsp;</th>
1172 <th class="value time">Time&nbsp;</th>
1173 <th class="value time">Percent▾&nbsp;</th>
1174 <th class="value count">Count&nbsp;</th>
1175 </tr>
1176 </thead>
1177 <tfoot>
1178 <tr>
1179 <td class="page">Total:</td>
1180 <td class="position"></td>
1181 <td class="value time"></td>
1182 <td class="value time"></td>
1183 <td class="value count"></td>
1184 </tr>
1185 </tfoot>
1186 <tbody></tbody>
1187 </table>
1188 </div>
1189 <div class="impactView inline">
1190 <h3>Impact list for <span></span></h3>
1191 <table class="pageDetailTable" onclick="handleSelectDetailRow(this, even t);">
1192 <thead>
1193 <tr>
1194 <th class="page">Name&nbsp;</th>
1195 <th class="value time">Time&nbsp;</th>
1196 <th class="value time">Percent▾&nbsp;</th>
1197 <th class="">Top Pages</th>
1198 </tr>
1199 </thead>
1200 <tbody></tbody>
1201 </table>
1202 </div>
1203 </div>
1204
1205 <div id="column" class="column">
1206 <div class="header">
1207 <select class="version" onchange="handleSelectVersion(this, event);"></s elect>
1208 <select class="pageVersion" onchange="handleSelectPage(this, event);"></ select>
1209 </div>
1210 <table class="list" onclick="handleSelectRow(this, event);">
1211 <thead>
1212 <tr>
1213 <th class="position">Pos.&nbsp;</th>
1214 <th class="name">Name&nbsp;</th>
1215 <th class="value time">Time&nbsp;</th>
1216 <th class="value time">Percent&nbsp;</th>
1217 <th class="value count">Count&nbsp;</th>
1218 </tr>
1219 </thead>
1220 <tbody></tbody>
1221 </table>
1222 </div>
1223 </div>
1224
1225 <div class="inline">
1226 <h2>Usage</h2>
1227 <ol>
1228 <li>Build chrome with the <a href="https://codereview.chromium.org/1923893 002">extended runtime callstats</a>.</li>
1229 <li>Run callstats.py with a web-page-replay archive:
1230 <pre>./callstats.py run \
1231 --replay-bin=$CHROME_SRC/third_party/webpagereplay/replay.py \
1232 --replay-wpr=top25.wpr \
1233 --js-flags="" \
1234 --with-chrome=$CHROME_SRC/out/Release/chrome \
1235 --sites-file=top25.json</pre>
1236 </li>
1237 <li>Move results file to a subdirectory: <code>mkdir $VERSION; mv *.txt $V ERSION</code></li>
1238 <li>Repeat from step 1 with a different configuration (e.g. <code>--js-fla gs="--nolazy"</code>).</li>
1239 <li>Create the final results file: <code>./callstats.py json $VERSION1 $VE RSION2 > result.json</code></li>
1240 <li>Use <code>results.json</code> on this site.</code>
1241 </ol>
1242 </div>
1243
1244 <div id="popover">
1245 <div class="popoverArrow"></div>
1246 <table>
1247 <tr>
1248 <td class="name" colspan="2"></td>
1249 </tr>
1250 <tr>
1251 <td>Page:</td>
1252 <td class="page"></td>
1253 </tr>
1254 <tr>
1255 <td>Version:</td>
1256 <td><span class="version"></span></td>
1257 <td class="compare"><span class="version"></span></td>
1258 </tr>
1259 <tr>
1260 <td>Time:</td>
1261 <td><span class="time"></span> ± <span class="timeVariance"></span></td>
1262 <td class="compare"><span class="time"></span> ± <span class="timeVarian ce"></span></td>
1263 </tr>
1264 <tr>
1265 <td>Percent:</td>
1266 <td><span class="percent"></span> ± <span class="percentVariance"></span ></td>
1267 <td class="compare"><span class="percent"></span> ± <span class="percent Variance"></span></td>
1268 </tr>
1269 <tr>
1270 <td>Count:</td>
1271 <td><span class="count"></span> ± <span class="countVariance"></span></t d>
1272 <td class="compare"><span class="count"></span> ± <span class="countVari ance"></span></td>
1273 </tr>
1274 <tr>
1275 <td>Overall Impact:</td>
1276 <td><span class="timeImpact"></span> / <span class="timePercentImpact">< /span></td>
1277 <td class="compare"><span class="timeImpact"></span> / <span class="time PercentImpact"></span></td>
1278 </tr>
1279 </table>
1280 </div>
1281
1282 </body>
1283
1284 </html>
OLDNEW
« no previous file with comments | « no previous file | tools/ic-explorer.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698