Index: tools/callstats.html |
diff --git a/tools/callstats.html b/tools/callstats.html |
index da85494f14c1bcd48e8b4f27bbc16fd76ded1914..afce1949721115aec4e3f623c0ce4fac1e2fc9b7 100644 |
--- a/tools/callstats.html |
+++ b/tools/callstats.html |
@@ -57,7 +57,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
#column { |
display: none; |
} |
- |
+ |
.list { |
width: 100%; |
} |
@@ -110,6 +110,15 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
background-color: #DDD; |
} |
+ .codeSearch { |
+ display: block-inline; |
+ float: right; |
+ border-radius: 5px; |
+ background-color: #EEE; |
+ width: 1em; |
+ text-align: center; |
+ } |
+ |
.list .position { |
text-align: right; |
display: none; |
@@ -207,6 +216,17 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
#popover .compare .version { |
padding-left: 10px; |
} |
+ .graph, |
+ .graph .content { |
+ width: 100%; |
+ } |
+ |
+ .diff .hideDiff { |
+ display: none; |
+ } |
+ .noDiff .hideNoDiff { |
+ display: none; |
+ } |
</style> |
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> |
<script type="text/javascript"> |
@@ -223,6 +243,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} |
var versions; |
+ var pages; |
var selectedPage; |
var baselineVersion; |
var selectedEntry; |
@@ -257,7 +278,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
var optgroup = document.createElement("optgroup"); |
optgroup.label = version.name; |
optgroup.version = version; |
- version.pages.forEach((page) => { |
+ version.forEachPage((page) => { |
var option = document.createElement("option"); |
option.textContent = page.name; |
option.page = page; |
@@ -280,22 +301,45 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
option.version = version; |
select.appendChild(option); |
}); |
+ initializeToggleList(versions.versions, $('versionSelector')); |
+ initializeToggleList(pages.values(), $('pageSelector')); |
+ initializeToggleContentVisibility(); |
+ } |
- var versionSelectorList = $('results').querySelector('.versionSelector ul'); |
- removeAllChildren(versionSelectorList); |
- versions.forEach((version) => { |
+ function initializeToggleList(items, node) { |
+ var list = node.querySelector('ul'); |
+ removeAllChildren(list); |
+ items = Array.from(items); |
+ items.sort(NameComparator); |
+ items.forEach((item) => { |
var li = document.createElement('li'); |
var checkbox = document.createElement('input'); |
checkbox.type = 'checkbox'; |
- checkbox.checked = version.enabled; |
- checkbox.version = version; |
+ checkbox.checked = item.enabled; |
+ checkbox.item = item; |
checkbox.addEventListener('click', handleToggleVersionEnable); |
li.appendChild(checkbox); |
- li.appendChild(document.createTextNode(version.name)); |
- versionSelectorList.appendChild(li); |
+ li.appendChild(document.createTextNode(item.name)); |
+ list.appendChild(li); |
}); |
$('results').querySelectorAll('#results > .hidden').forEach((node) => { |
toggleCssClass(node, 'hidden', false); |
+ }) |
+ } |
+ |
+ function initializeToggleContentVisibility() { |
+ var nodes = document.querySelectorAll('.toggleContentVisibility'); |
+ nodes.forEach((node) => { |
+ var content = node.querySelector('.content'); |
+ var header = node.querySelector('h1,h2,h3'); |
+ if (content === undefined || header === undefined) return; |
+ if (header.querySelector('input') != undefined) return; |
+ var checkbox = document.createElement('input'); |
+ checkbox.type = 'checkbox'; |
+ checkbox.checked = content.className.indexOf('hidden') == -1; |
+ checkbox.contentNode = content; |
+ checkbox.addEventListener('click', handleToggleContentVisibility); |
+ header.insertBefore(checkbox, header.childNodes[0]); |
}); |
} |
@@ -306,7 +350,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
selectedPage.sort(); |
showPageInColumn(firstPage, 0); |
// Show the other versions of this page in the following columns. |
- var pageVersions = versions.pageVersions(firstPage.name); |
+ var pageVersions = versions.getPageVersions(firstPage); |
var index = 1; |
pageVersions.forEach((page) => { |
if (page !== firstPage) { |
@@ -385,7 +429,9 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} else { |
td(tr, entry.position == 0 ? '' : entry.position, 'position'); |
} |
- td(tr, entry.name, 'name ' + entry.cssClass()); |
+ addCodeSearchButton(entry, |
+ td(tr, entry.name, 'name ' + entry.cssClass())); |
+ |
diffStatus( |
td(tr, ms(entry.time), 'value time'), |
entry.time, referenceEntry.time); |
@@ -398,18 +444,19 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} else if (baselineVersion !== undefined && referenceEntry |
&& page.version !== baselineVersion) { |
// Show comparison of entry that does not exist on the current page. |
- tr.entry = referenceEntry; |
+ tr.entry = new Entry(0, referenceEntry.name); |
+ tr.entry.page = page; |
td(tr, '-', 'position'); |
td(tr, referenceEntry.name, 'name'); |
diffStatus( |
- td(tr, ms(referenceEntry.time), 'value time'), |
- referenceEntry.time, 0); |
+ td(tr, ms(-referenceEntry.time), 'value time'), |
+ -referenceEntry.time, 0); |
diffStatus( |
- td(tr, percent(referenceEntry.timePercent), 'value time'), |
- referenceEntry.timePercent, 0); |
+ td(tr, percent(-referenceEntry.timePercent), 'value time'), |
+ -referenceEntry.timePercent, 0); |
diffStatus( |
- td(tr, count(referenceEntry.count), 'value count'), |
- referenceEntry.count, 0); |
+ td(tr, count(-referenceEntry.count), 'value count'), |
+ -referenceEntry.count, 0); |
} else { |
// Display empty entry / baseline entry |
var showBaselineEntry = entry !== undefined; |
@@ -444,7 +491,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
if (updateSelectedPage) { |
entry = selectedPage.version.getEntry(entry); |
} |
- var rowIndex; |
+ var rowIndex = 0; |
var needsPageSwitch = updateSelectedPage && entry.page != selectedPage; |
// If clicked in the detail row change the first column to that page. |
if (needsPageSwitch) showPage(entry.page); |
@@ -478,13 +525,20 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} |
function showEntryDetail(entry) { |
+ showVersionDetails(entry); |
+ showPageDetails(entry); |
+ showImpactList(entry.page); |
+ showGraphs(entry.page); |
+ } |
+ |
+ function showVersionDetails(entry) { |
var table, tbody, entries; |
table = $('detailView').querySelector('.versionDetailTable'); |
tbody = document.createElement('tbody'); |
if (entry !== undefined) { |
$('detailView').querySelector('.versionDetail h3 span').innerHTML = |
- entry.name; |
- entries = versions.pageVersions(entry.page.name).map( |
+ entry.name + ' in ' + entry.page.name; |
+ entries = versions.getPageVersions(entry.page).map( |
(page) => { |
return page.get(entry.name) |
}); |
@@ -496,53 +550,59 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
var tr = document.createElement('tr'); |
if (pageEntry == entry) tr.className += 'selected'; |
tr.entry = pageEntry; |
+ var isBaselineEntry = pageEntry.page.version == baselineVersion; |
td(tr, pageEntry.page.version.name, 'version'); |
- td(tr, pageEntry.position, 'value position'); |
- td(tr, ms(pageEntry.time), 'value time'); |
- td(tr, percent(pageEntry.timePercent), 'value time'); |
- td(tr, count(pageEntry.count), 'value count'); |
+ td(tr, ms(pageEntry.time, !isBaselineEntry), 'value time'); |
+ td(tr, percent(pageEntry.timePercent, !isBaselineEntry), 'value time'); |
+ td(tr, count(pageEntry.count, !isBaselineEntry), 'value count'); |
tbody.appendChild(tr); |
}); |
} |
table.replaceChild(tbody, table.querySelector('tbody')); |
+ } |
+ function showPageDetails(entry) { |
+ var table, tbody, entries; |
table = $('detailView').querySelector('.pageDetailTable'); |
tbody = document.createElement('tbody'); |
- if (entry !== undefined) { |
- var version = entry.page.version; |
- $('detailView').querySelector('.pageDetail h3 span').innerHTML = |
- version.name; |
- entries = version.pages.map( |
- (page) => { |
- return page.get(entry.name) |
- }); |
- entries.sort((a, b) => { |
- var cmp = b.timePercent - a.timePercent; |
- if (cmp.toFixed(1) == 0) return b.time - a.time; |
- return cmp |
- }); |
- entries.forEach((pageEntry) => { |
- if (pageEntry === undefined) return; |
- var tr = document.createElement('tr'); |
- if (pageEntry === entry) tr.className += 'selected'; |
- tr.entry = pageEntry; |
- td(tr, pageEntry.page.name, 'name'); |
- td(tr, pageEntry.position, 'value position'); |
- td(tr, ms(pageEntry.time), 'value time'); |
- td(tr, percent(pageEntry.timePercent), 'value time'); |
- td(tr, count(pageEntry.count), 'value count'); |
- tbody.appendChild(tr); |
- }); |
- // show the total for all pages |
- var tds = table.querySelectorAll('tfoot td'); |
- tds[2].innerHTML = ms(entry.getTimeImpact()); |
- // Only show the percentage total if we are in diff mode: |
- tds[3].innerHTML = percent(entry.getTimePercentImpact()); |
- tds[4].innerHTML = count(entry.getCountImpact()); |
+ if (entry === undefined) { |
+ table.replaceChild(tbody, table.querySelector('tbody')); |
+ return; |
} |
+ var version = entry.page.version; |
+ var showDiff = version !== baselineVersion; |
+ $('detailView').querySelector('.pageDetail h3 span').innerHTML = |
+ version.name; |
+ entries = version.pages.map((page) => { |
+ if (!page.enabled) return; |
+ return page.get(entry.name) |
+ }); |
+ entries.sort((a, b) => { |
+ var cmp = b.timePercent - a.timePercent; |
+ if (cmp.toFixed(1) == 0) return b.time - a.time; |
+ return cmp |
+ }); |
+ entries.forEach((pageEntry) => { |
+ if (pageEntry === undefined) return; |
+ var tr = document.createElement('tr'); |
+ if (pageEntry === entry) tr.className += 'selected'; |
+ tr.entry = pageEntry; |
+ td(tr, pageEntry.page.name, 'name'); |
+ td(tr, ms(pageEntry.time, showDiff), 'value time'); |
+ td(tr, percent(pageEntry.timePercent, showDiff), 'value time'); |
+ td(tr, percent(pageEntry.timePercentPerEntry, showDiff), |
+ 'value time hideNoDiff'); |
+ td(tr, count(pageEntry.count, showDiff), 'value count'); |
+ tbody.appendChild(tr); |
+ }); |
+ // show the total for all pages |
+ var tds = table.querySelectorAll('tfoot td'); |
+ tds[1].innerHTML = ms(entry.getTimeImpact(), showDiff); |
+ // Only show the percentage total if we are in diff mode: |
+ tds[2].innerHTML = percent(entry.getTimePercentImpact(), showDiff); |
+ tds[3].innerHTML = ''; |
+ tds[4].innerHTML = count(entry.getCountImpact(), showDiff); |
table.replaceChild(tbody, table.querySelector('tbody')); |
- showImpactList(entry.page); |
- showPageGraphs(entry.page); |
} |
function showImpactList(page) { |
@@ -593,62 +653,192 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
table.replaceChild(tbody, table.querySelector('tbody')); |
} |
- var selectedGroup; |
- function showPageGraphs(page) { |
- var groups = page.groups.filter(each => each.name != page.total.name); |
+ function showGraphs(page) { |
+ var groups = page.groups.slice(); |
+ // Sort groups by the biggest impact |
+ groups.sort((a, b) => { |
+ return b.getTimeImpact() - a.getTimeImpact(); |
+ }); |
if (selectedGroup == undefined) { |
selectedGroup = groups[0]; |
} else { |
groups = groups.filter(each => each.name != selectedGroup.name); |
groups.unshift(selectedGroup); |
} |
+ showPageGraph(groups, page); |
+ showVersionGraph(groups, page); |
+ showPageVersionGraph(groups, page); |
+ } |
+ |
+ function getGraphDataTable(groups) { |
var dataTable = new google.visualization.DataTable(); |
dataTable.addColumn('string', 'Name'); |
groups.forEach(group => { |
- var column = dataTable.addColumn('number', group.name); |
+ var column = dataTable.addColumn('number', group.name.substring(6)); |
dataTable.setColumnProperty(column, 'group', group); |
}); |
+ return dataTable; |
+ } |
+ |
+ var selectedGroup; |
+ function showPageGraph(groups, page) { |
+ var isDiffView = baselineVersion !== undefined; |
+ var dataTable = getGraphDataTable(groups); |
// Calculate the average row |
var row = ['Average']; |
groups.forEach((group) => { |
- row.push(group.getTimeImpact()); |
+ if (isDiffView) { |
+ row.push(group.isTotal ? 0 : group.getAverageTimeImpact()); |
+ } else { |
+ row.push(group.isTotal ? 0 : group.getTimeImpact()); |
+ } |
}); |
dataTable.addRow(row); |
// Sort the pages by the selected group. |
- var pages = page.version.pages.slice(); |
- pages.sort((a, b) => { |
- return b.getEntry(selectedGroup).timePercent - a.getEntry(selectedGroup).timePercent; |
- }); |
+ var pages = page.version.pages.filter(page => page.enabled); |
+ function sumDiff(page) { |
+ var sum = 0; |
+ groups.forEach(group => { |
+ var value = group.getTimePercentImpact() - |
+ page.getEntry(group).timePercent; |
+ sum += value * value; |
+ }); |
+ return sum; |
+ } |
+ if (isDiffView) { |
+ pages.sort((a, b) => { |
+ return b.getEntry(selectedGroup).time- |
+ a.getEntry(selectedGroup).time; |
+ }); |
+ } else { |
+ pages.sort((a, b) => { |
+ return b.getEntry(selectedGroup).timePercent - |
+ a.getEntry(selectedGroup).timePercent; |
+ }); |
+ } |
+ // Sort by sum of squared distance to the average. |
+ // pages.sort((a, b) => { |
+ // return a.distanceFromTotalPercent() - b.distanceFromTotalPercent(); |
+ // }); |
// Calculate the entries for the pages |
pages.forEach((page) => { |
row = [page.name]; |
groups.forEach((group) => { |
- row.push(page.getEntry(group).time); |
+ row.push(group.isTotal ? 0 : page.getEntry(group).time); |
}); |
- dataTable.addRow(row); |
+ var rowIndex = dataTable.addRow(row); |
+ dataTable.setRowProperty(rowIndex, 'page', page); |
}); |
+ renderGraph('Pages for ' + page.version.name, groups, dataTable, |
+ 'pageGraph', isDiffView ? true : 'percent'); |
+ } |
- var height = 1000/27*page.version.pages.length; |
+ function showVersionGraph(groups, page) { |
+ var dataTable = getGraphDataTable(groups); |
+ var row; |
+ var vs = versions.versions.filter(version => version.enabled); |
+ vs.sort((a, b) => { |
+ return b.getEntry(selectedGroup).getTimeImpact() - |
+ a.getEntry(selectedGroup).getTimeImpact(); |
+ }); |
+ // Calculate the entries for the versions |
+ vs.forEach((version) => { |
+ row = [version.name]; |
+ groups.forEach((group) => { |
+ row.push(group.isTotal ? 0 : version.getEntry(group).getTimeImpact()); |
+ }); |
+ var rowIndex = dataTable.addRow(row); |
+ dataTable.setRowProperty(rowIndex, 'page', page); |
+ }); |
+ renderGraph('Versions Total Time over all Pages', groups, dataTable, |
+ 'versionGraph', true); |
+ } |
+ |
+ function showPageVersionGraph(groups, page) { |
+ var dataTable = getGraphDataTable(groups); |
+ var row; |
+ var vs = versions.getPageVersions(page); |
+ vs.sort((a, b) => { |
+ return b.getEntry(selectedGroup).time - a.getEntry(selectedGroup).time; |
+ }); |
+ // Calculate the entries for the versions |
+ vs.forEach((page) => { |
+ row = [page.version.name]; |
+ groups.forEach((group) => { |
+ row.push(group.isTotal ? 0 : page.getEntry(group).time); |
+ }); |
+ var rowIndex = dataTable.addRow(row); |
+ dataTable.setRowProperty(rowIndex, 'page', page); |
+ }); |
+ renderGraph('Versions for ' + page.name, groups, dataTable, |
+ 'pageVersionGraph', true); |
+ } |
+ |
+ function renderGraph(title, groups, dataTable, id, isStacked) { |
+ var isDiffView = baselineVersion !== undefined; |
+ var formatter = new google.visualization.NumberFormat({ |
+ suffix: (isDiffView ? 'msΔ' : 'ms'), |
+ negativeColor: 'red', |
+ groupingSymbol: "'" |
+ }); |
+ for (var i = 1; i < dataTable.getNumberOfColumns(); i++) { |
+ formatter.format(dataTable, i); |
+ } |
+ var height = 85 + 28 * dataTable.getNumberOfRows(); |
var options = { |
- title: 'Page Comparison for Version ' + page.version.name, |
- isStacked: 'percent', |
- height: height , |
+ isStacked: isStacked, |
+ height: height, |
hAxis: { |
- title: '% Time', |
minValue: 0, |
}, |
+ animation:{ |
+ duration: 500, |
+ easing: 'out', |
+ }, |
vAxis: { |
- } |
+ }, |
+ explorer: { |
+ actions: ['dragToZoom', 'rightClickToReset'], |
+ maxZoomIn: 0.01 |
+ }, |
+ legend: {position:'top', textStyle:{fontSize: '16px'}}, |
+ chartArea: {left:200, top:50, width:'98%', height:'80%'}, |
+ colors: groups.map(each => each.color) |
}; |
- var chart = new google.visualization.BarChart($('pageGraphs')); |
- chart.draw(dataTable, options); |
+ var parentNode = $(id); |
+ parentNode.querySelector('h2>span, h3>span').innerHTML = title; |
+ var graphNode = parentNode.querySelector('.content'); |
+ |
+ var chart = graphNode.chart; |
+ if (chart === undefined) { |
+ chart = graphNode.chart = new google.visualization.BarChart(graphNode); |
+ } else { |
+ google.visualization.events.removeAllListeners(chart); |
+ } |
google.visualization.events.addListener(chart, 'select', selectHandler); |
+ function getChartEntry(selection) { |
+ if (!selection) return undefined; |
+ var column = selection.column; |
+ if (column == undefined) return undefined; |
+ var selectedGroup = dataTable.getColumnProperty(column, 'group'); |
+ var row = selection.row; |
+ if (row == null) return selectedGroup; |
+ var page = dataTable.getRowProperty(row, 'page'); |
+ if (!page) return selectedGroup; |
+ return page.getEntry(selectedGroup); |
+ } |
function selectHandler() { |
- var column = chart.getSelection()[0].column; |
- if (column === undefined) return; |
- selectedGroup = dataTable.getColumnProperty(column, 'group'); |
- showPageGraphs(selectedEntry.page); |
+ selectedGroup = getChartEntry(chart.getSelection()[0]) |
+ if (!selectedGroup) return; |
+ selectEntry(selectedGroup, true); |
} |
+ |
+ // Make our global tooltips work |
+ google.visualization.events.addListener(chart, 'onmouseover', mouseOverHandler); |
+ function mouseOverHandler(selection) { |
+ graphNode.entry = getChartEntry(selection); |
+ } |
+ chart.draw(dataTable, options); |
} |
function showGroup(entry) { |
@@ -684,6 +874,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
node('.time').innerHTML = '-'; |
node('.timeVariance').innerHTML = '-'; |
node('.percent').innerHTML = '-'; |
+ node('.percentPerEntry').innerHTML = '-'; |
node('.percentVariance').innerHTML = '-'; |
node('.count').innerHTML = '-'; |
node('.countVariance').innerHTML = '-'; |
@@ -695,6 +886,8 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
node('.timeVariance').innerHTML |
= percent(entry.timeVariancePercent, false); |
node('.percent').innerHTML = percent(entry.timePercent, false); |
+ node('.percentPerEntry').innerHTML |
+ = percent(entry.timePercentPerEntry, false); |
node('.percentVariance').innerHTML |
= percent(entry.timePercentVariancePercent, false); |
node('.count').innerHTML = count(entry._count, false); |
@@ -706,8 +899,10 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
= percent(entry.getTimeImpactVariancePercent(false), false); |
} |
} |
- |
- // =========================================================================== |
+ </script> |
+ <script type="text/javascript"> |
+ "use strict" |
+ // ========================================================================= |
// Helpers |
function $(id) { |
return document.getElementById(id) |
@@ -729,6 +924,16 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} |
} |
+ function addCodeSearchButton(entry, node) { |
+ if (entry.isGroup) return; |
+ var button = document.createElement("div"); |
+ button.innerHTML = '?' |
+ button.className = "codeSearch" |
+ button.addEventListener('click', handleCodeSearch); |
+ node.appendChild(button); |
+ return node; |
+ } |
+ |
function td(tr, content, className) { |
var td = document.createElement("td"); |
td.innerHTML = content; |
@@ -765,8 +970,15 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
node.className = classes.join(' '); |
} |
+ function NameComparator(a, b) { |
+ if (a.name > b.name) return 1; |
+ if (a.name < b.name) return -1; |
+ return 0 |
+ } |
+ |
function diffSign(value, digits, unit, showDiff) { |
if (showDiff === false || baselineVersion == undefined) { |
+ if (value === undefined) return ''; |
return value.toFixed(digits) + unit; |
} |
return (value >= 0 ? '+' : '') + value.toFixed(digits) + unit + 'Δ'; |
@@ -784,6 +996,9 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
return diffSign(value, 1, '%', showDiff); |
} |
+ </script> |
+ <script type="text/javascript"> |
+ "use strict" |
// ========================================================================= |
// EventHandlers |
function handleBodyLoad() { |
@@ -796,6 +1011,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
var reader = new FileReader(); |
reader.onload = function(evt) { |
+ pages = new Pages(); |
versions = Versions.fromJSON(JSON.parse(this.result)); |
initialize() |
showPage(versions.versions[0].pages[0]); |
@@ -827,7 +1043,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} else { |
var columnIndex = select.id.split('_')[1]; |
var pageSelect = $('select_' + columnIndex); |
- var page = pageSelect.options[select.selectedIndex].page; |
+ var page = pageSelect.options[pageSelect.selectedIndex].page; |
page = version.get(page.name); |
showPageInColumn(page, columnIndex); |
} |
@@ -851,29 +1067,40 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
function handleSelectBaseline(select, event) { |
var option = select.options[select.selectedIndex]; |
- baselineVersion = option.version |
+ baselineVersion = option.version; |
+ var showingDiff = baselineVersion !== undefined; |
+ var body = $('body'); |
+ toggleCssClass(body, 'diff', showingDiff); |
+ toggleCssClass(body, 'noDiff', !showingDiff); |
showPage(selectedPage); |
if (selectedEntry === undefined) return; |
selectEntry(selectedEntry, true); |
} |
+ function findEntry(event) { |
+ var target = event.target; |
+ while (target.entry === undefined) { |
+ target = target.parentNode; |
+ if (!target) return undefined; |
+ } |
+ return target.entry; |
+ } |
+ |
function handleUpdatePopover(event) { |
var popover = $('popover'); |
popover.style.left = event.pageX + 'px'; |
popover.style.top = event.pageY + 'px'; |
+ popover.style.display = 'none'; |
popover.style.display = event.shiftKey ? 'block' : 'none'; |
- var target = event.target; |
- while (target.entry === undefined) { |
- target = target.parentNode; |
- if (!target) return; |
- } |
- showPopover(target.entry); |
+ var entry = findEntry(event); |
+ if (entry === undefined) return; |
+ showPopover(entry); |
} |
function handleToggleVersionEnable(event) { |
- var version = this.version; |
- if (version === undefined) return; |
- version.enabled = this.checked; |
+ var item = this.item ; |
+ if (item === undefined) return; |
+ item .enabled = this.checked; |
initialize(); |
var page = selectedPage; |
if (page === undefined || !page.version.enabled) { |
@@ -882,8 +1109,26 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
showPage(page); |
} |
- // =========================================================================== |
+ function handleToggleContentVisibility(event) { |
+ var content = event.target.contentNode; |
+ toggleCssClass(content, 'hidden'); |
+ } |
+ function handleCodeSearch(event) { |
+ var entry = findEntry(event); |
+ if (entry === undefined) return; |
+ var url = "https://cs.chromium.org/search/?sq=package:chromium&type=cs&q="; |
+ name = entry.name; |
+ if (name.startsWith("API_")) { |
+ name = name.substring(4); |
+ } |
+ url += encodeURIComponent(name) + "+file:src/v8/src"; |
+ window.open(url,'_blank'); |
+ } |
+ </script> |
+ <script type="text/javascript"> |
+ "use strict" |
+ // ========================================================================= |
class Versions { |
constructor() { |
this.versions = []; |
@@ -891,12 +1136,12 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
add(version) { |
this.versions.push(version) |
} |
- pageVersions(name) { |
+ getPageVersions(page) { |
var result = []; |
this.versions.forEach((version) => { |
if (!version.enabled) return; |
- var page = version.get(name); |
- if (page !== undefined) result.push(page); |
+ var versionPage = version.get(page.name); |
+ if (versionPage !== undefined) result.push(versionPage); |
}); |
return result; |
} |
@@ -910,11 +1155,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
this.versions.forEach(f); |
} |
sort() { |
- this.versions.sort((a, b) => { |
- if (a.name > b.name) return 1; |
- if (a.name < b.name) return -1; |
- return 0 |
- }) |
+ this.versions.sort(NameComparator); |
} |
getEnabledPage(name) { |
for (var i = 0; i < this.versions.length; i++) { |
@@ -922,7 +1163,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
if (!version.enabled) continue; |
var page = version.get(name); |
if (page !== undefined) return page; |
- } |
+ } |
} |
} |
Versions.fromJSON = function(json) { |
@@ -964,10 +1205,16 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
return page.get(entry.name); |
} |
forEachEntry(fun) { |
- this.pages.forEach((page) => { |
+ this.forEachPage((page) => { |
page.forEach(fun); |
}); |
} |
+ forEachPage(fun) { |
+ this.pages.forEach((page) => { |
+ if (!page.enabled) return; |
+ fun(page); |
+ }) |
+ } |
allEntries() { |
var map = new Map(); |
this.forEachEntry((group, entry) => { |
@@ -978,7 +1225,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
getTotalValue(name, property) { |
if (name === undefined) name = this.pages[0].total.name; |
var sum = 0; |
- this.pages.forEach((page) => { |
+ this.forEachPage((page) => { |
var entry = page.get(name); |
if (entry !== undefined) sum += entry[property]; |
}); |
@@ -988,19 +1235,20 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
return this.getTotalValue(name, showDiff === false ? '_time' : 'time'); |
} |
getTotalTimePercent(name, showDiff) { |
- if (baselineVersion === undefined) { |
+ if (baselineVersion === undefined || showDiff === false) { |
// Return the overall average percent of the given entry name. |
return this.getTotalValue(name, 'time') / |
this.getTotalTime('Group-Total') * 100; |
} |
// Otherwise return the difference to the sum of the baseline version. |
var baselineValue = baselineVersion.getTotalTime(name, false); |
- return this.getTotalValue(name, '_time') / baselineValue * 100; |
+ var total = this.getTotalValue(name, '_time'); |
+ return (total / baselineValue - 1) * 100; |
} |
getTotalTimeVariance(name, showDiff) { |
// Calculate the overall error for a given entry name |
var sum = 0; |
- this.pages.forEach((page) => { |
+ this.forEachPage((page) => { |
var entry = page.get(name); |
if (entry === undefined) return; |
sum += entry.timeVariance * entry.timeVariance; |
@@ -1014,6 +1262,9 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
getTotalCount(name, showDiff) { |
return this.getTotalValue(name, showDiff === false ? '_count' : 'count'); |
} |
+ getAverageTimeImpact(name, showDiff) { |
+ return this.getTotalTime(name, showDiff) / this.pages.length; |
+ } |
getPagesByPercentImpact(name) { |
var sortedPages = |
this.pages.filter((each) => { |
@@ -1025,38 +1276,60 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
return sortedPages; |
} |
sort() { |
- this.pages.sort((a, b) => { |
- if (a.name > b.name) return 1; |
- if (a.name < b.name) return -1; |
- return 0 |
- }) |
+ this.pages.sort(NameComparator) |
} |
} |
Version.fromJSON = function(name, data) { |
var version = new Version(name); |
- for (var page in data) { |
- version.add(Page.fromJSON(version, page, data[page])); |
+ for (var pageName in data) { |
+ version.add(PageVersion.fromJSON(version, pageName, data[pageName])); |
} |
version.sort(); |
return version; |
} |
- |
+ |
+ class Pages extends Map { |
+ get(name) { |
+ if (name.indexOf('www.') == 0) { |
+ name = name.substring(4); |
+ } |
+ if (!this.has(name)) { |
+ this.set(name, new Page(name)); |
+ } |
+ return super.get(name); |
+ } |
+ } |
class Page { |
- constructor(version, name) { |
+ constructor(name) { |
this.name = name; |
- this.total = new GroupedEntry('Total', /.*Total.*/); |
- this.unclassified = new UnclassifiedEntry(this) |
+ this.enabled = true; |
+ this.versions = []; |
+ } |
+ add(page) { |
+ this.versions.push(page); |
+ } |
+ } |
+ |
+ class PageVersion { |
+ constructor(version, page) { |
+ this.page = page; |
+ this.page.add(this); |
+ this.total = new GroupedEntry('Total', /.*Total.*/, '#BBB'); |
+ this.total.isTotal = true; |
+ this.unclassified = new UnclassifiedEntry(this, "#000") |
this.groups = [ |
this.total, |
- new GroupedEntry('IC', /.*IC.*/), |
+ new GroupedEntry('IC', /.*IC.*/, "#3366CC"), |
new GroupedEntry('Optimize', |
- /StackGuard|.*Optimize.*|.*Deoptimize.*|Recompile.*/), |
- new GroupedEntry('Compile', /.*Compile.*|Parse.*/), |
- new GroupedEntry('Callback', /.*Callback$/), |
- new GroupedEntry('API', /.*API.*/), |
- new GroupedEntry('GC', /GC|AllocateInTargetSpace/), |
- new GroupedEntry('JavaScript', /JS_Execution/), |
+ /StackGuard|.*Optimize.*|.*Deoptimize.*|Recompile.*/, "#DC3912"), |
+ new GroupedEntry('Compile', /.*Compile.*/, "#FFAA00"), |
+ new GroupedEntry('Parse', /.*Parse.*/, "#FF6600"), |
+ new GroupedEntry('Callback', /.*Callback$/, "#109618"), |
+ new GroupedEntry('API', /.*API.*/, "#990099"), |
+ new GroupedEntry('GC', /GC|AllocateInTargetSpace/, "#0099C6"), |
+ new GroupedEntry('JavaScript', /JS_Execution/, "#DD4477"), |
+ new GroupedEntry('Runtime', /.*/, "#88BB00"), |
this.unclassified |
]; |
this.entryDict = new Map(); |
@@ -1086,8 +1359,11 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
get length() { |
return this.versions.length |
} |
+ get name() { return this.page.name } |
+ get enabled() { return this.page.enabled } |
forEachSorted(referencePage, func) { |
- // Iterate over all the entries in the order they appear on the reference page. |
+ // Iterate over all the entries in the order they appear on the |
+ // reference page. |
referencePage.forEach((parent, referenceEntry) => { |
var entry; |
if (parent) parent = this.entryDict.get(parent.name); |
@@ -1114,12 +1390,19 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
group.sort() |
}); |
} |
- } |
- Page.fromJSON = function(version, name, data) { |
- if (name.indexOf('www.') == 0) { |
- name = name.substring(4); |
+ distanceFromTotalPercent() { |
+ var sum = 0; |
+ this.groups.forEach(group => { |
+ if (group == this.total) return; |
+ var value = group.getTimePercentImpact() - |
+ this.getEntry(group).timePercent; |
+ sum += value * value; |
+ }); |
+ return sum; |
} |
- var page = new Page(version, name); |
+ } |
+ PageVersion.fromJSON = function(version, name, data) { |
+ var page = new PageVersion(version, pages.get(name)); |
for (var i = 0; i < data.length; i++) { |
page.add(Entry.fromJSON(i, data[data.length - i - 1])); |
} |
@@ -1142,6 +1425,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
this.countVariancePercent = countVariancePercent; |
this.page = undefined; |
this.parent = undefined; |
+ this.isTotal = false; |
} |
getCompareWithBaseline(value, property) { |
if (baselineVersion == undefined) return value; |
@@ -1168,6 +1452,14 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
return (this._time - baselineEntry._time) / this.page.total._time * |
100; |
} |
+ get timePercentPerEntry() { |
+ var value = this._time / this.page.total._time * 100; |
+ if (baselineVersion == undefined) return value; |
+ var baselineEntry = baselineVersion.getEntry(this); |
+ if (!baselineEntry) return value; |
+ if (baselineVersion === this.page.version) return value; |
+ return (this._time / baselineEntry._time - 1) * 100; |
+ } |
get timePercentVariancePercent() { |
// Get the absolute values for the percentages |
return this.timeVariance / this.page.total._time * 100; |
@@ -1184,6 +1476,9 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
getCountImpact(showDiff) { |
return this.page.version.getTotalCount(this.name, showDiff); |
} |
+ getAverageTimeImpact(showDiff) { |
+ return this.page.version.getAverageTimeImpact(this.name, showDiff); |
+ } |
getPagesByPercentImpact() { |
return this.page.version.getPagesByPercentImpact(this.name); |
} |
@@ -1203,9 +1498,10 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
class GroupedEntry extends Entry { |
- constructor(name, regexp) { |
+ constructor(name, regexp, color) { |
super(0, 'Group-' + name, 0, 0, 0, 0, 0, 0); |
this.regexp = regexp; |
+ this.color = color; |
this.entries = []; |
} |
add(entry) { |
@@ -1222,8 +1518,8 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
this.entries.forEach(fun); |
return; |
} |
- // If we have a baslineVersion to compare against show also all entries from the |
- // other group. |
+ // If we have a baslineVersion to compare against show also all entries |
+ // from the other group. |
var tmpEntries = baselineVersion.getEntry(this) |
.entries.filter((entry) => { |
return this.page.get(entry.name) == undefined |
@@ -1271,8 +1567,8 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
} |
class UnclassifiedEntry extends GroupedEntry { |
- constructor(page) { |
- super('Runtime'); |
+ constructor(page, color) { |
+ super('Unclassified', undefined, color); |
this.page = page; |
this._time = undefined; |
this._count = undefined; |
@@ -1311,7 +1607,7 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
</script> |
</head> |
-<body onmousemove="handleUpdatePopover(event)" onload="handleBodyLoad()"> |
+<body id="body" onmousemove="handleUpdatePopover(event)" onload="handleBodyLoad()" class="noDiff"> |
<h1>Runtime Stats Komparator</h1> |
<div id="results"> |
@@ -1331,71 +1627,97 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
<span style="color: #060">Green</span> the selected version above performs |
better on this measurement. |
</div> |
- <div class="versionSelector inline"> |
- Select Versions: |
+ </div> |
+ |
+ <div id="versionSelector" class="inline toggleContentVisibility"> |
+ <h2>Version Selector</h2> |
+ <div class="content hidden"> |
<ul></ul> |
</div> |
</div> |
+ |
+ <div id="pageSelector" class="inline toggleContentVisibility"> |
+ <h2>Page Selector</h2> |
+ <div class="content hidden"> |
+ <ul></ul> |
+ </div> |
+ </div> |
+ |
<div id="view"> |
</div> |
<div id="detailView" class="hidden"> |
- <h2></h2> |
- <div class="versionDetail inline"> |
- <h3>Version Comparison for <span></span></h3> |
- <table class="versionDetailTable" onclick="handleSelectDetailRow(this, event);"> |
- <thead> |
- <tr> |
- <th class="version">Version </th> |
- <th class="position">Pos. </th> |
- <th class="value time">Time▴ </th> |
- <th class="value time">Percent </th> |
- <th class="value count">Count </th> |
- </tr> |
- </thead> |
- <tbody></tbody> |
- </table> |
+ <div class="versionDetail inline toggleContentVisibility"> |
+ <h3><span></span></h3> |
+ <div class="content"> |
+ <table class="versionDetailTable" onclick="handleSelectDetailRow(this, event);"> |
+ <thead> |
+ <tr> |
+ <th class="version">Version </th> |
+ <th class="position">Pos. </th> |
+ <th class="value time">Time▴ </th> |
+ <th class="value time">Percent </th> |
+ <th class="value count">Count </th> |
+ </tr> |
+ </thead> |
+ <tbody></tbody> |
+ </table> |
+ </div> |
</div> |
- <div class="pageDetail inline"> |
+ <div class="pageDetail inline toggleContentVisibility"> |
<h3>Page Comparison for <span></span></h3> |
- <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);"> |
- <thead> |
- <tr> |
- <th class="page">Page </th> |
- <th class="position">Pos. </th> |
- <th class="value time">Time </th> |
- <th class="value time">Percent▾ </th> |
- <th class="value count">Count </th> |
- </tr> |
- </thead> |
- <tfoot> |
- <tr> |
- <td class="page">Total:</td> |
- <td class="position"></td> |
- <td class="value time"></td> |
- <td class="value time"></td> |
- <td class="value count"></td> |
- </tr> |
- </tfoot> |
- <tbody></tbody> |
- </table> |
+ <div class="content"> |
+ <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);"> |
+ <thead> |
+ <tr> |
+ <th class="page">Page </th> |
+ <th class="value time">Time </th> |
+ <th class="value time">Percent▾ </th> |
+ <th class="value time hideNoDiff">%/Entry </th> |
+ <th class="value count">Count </th> |
+ </tr> |
+ </thead> |
+ <tfoot> |
+ <tr> |
+ <td class="page">Total:</td> |
+ <td class="value time"></td> |
+ <td class="value time"></td> |
+ <td class="value time hideNoDiff"></td> |
+ <td class="value count"></td> |
+ </tr> |
+ </tfoot> |
+ <tbody></tbody> |
+ </table> |
+ </div> |
</div> |
- <div class="impactView inline"> |
+ <div class="impactView inline toggleContentVisibility"> |
<h3>Impact list for <span></span></h3> |
- <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);"> |
- <thead> |
- <tr> |
- <th class="page">Name </th> |
- <th class="value time">Time </th> |
- <th class="value time">Percent▾ </th> |
- <th class="">Top Pages</th> |
- </tr> |
- </thead> |
- <tbody></tbody> |
- </table> |
+ <div class="content"> |
+ <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);"> |
+ <thead> |
+ <tr> |
+ <th class="page">Name </th> |
+ <th class="value time">Time </th> |
+ <th class="value time">Percent▾ </th> |
+ <th class="">Top Pages</th> |
+ </tr> |
+ </thead> |
+ <tbody></tbody> |
+ </table> |
+ </div> |
</div> |
</div> |
- <div id="pageGraphs" class="hidden"> |
+ <div id="pageVersionGraph" class="graph hidden toggleContentVisibility"> |
+ <h3><span></span></h3> |
+ <div class="content"></div> |
+ </div> |
+ <div id="pageGraph" class="graph hidden toggleContentVisibility"> |
+ <h3><span></span></h3> |
+ <div class="content"></div> |
+ </div> |
+ <div id="versionGraph" class="graph hidden toggleContentVisibility"> |
+ <h3><span></span></h3> |
+ <div class="content"></div> |
</div> |
<div id="column" class="column"> |
@@ -1464,6 +1786,11 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
<td class="compare percent"></td><td class="compare"> ± </td><td class="compare percentVariance"></td> |
</tr> |
<tr> |
+ <td>Percent per Entry:</td> |
+ <td class="percentPerEntry"></td><td colspan=2></td> |
+ <td class="compare percentPerEntry"></td><td colspan=2></td> |
+ </tr> |
+ <tr> |
<td>Count:</td> |
<td class="count"></td><td>±</td><td class="countVariance"></td> |
<td class="compare count"></td><td class="compare"> ± </td><td class="compare countVariance"></td> |
@@ -1475,7 +1802,5 @@ code is governed by a BSD-style license that can be found in the LICENSE file. |
</tr> |
</table> |
</div> |
- |
</body> |
- |
</html> |