blob: a9171c5fe7c17571274be27de86db57a46a2c7dd [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>R8 perf</title>
</head>
<body>
<select id="benchmark-selector"></select>
<div>
<canvas id="myChart"></canvas>
</div>
<div>
<div style="float: left; width: 50%">
<button type="button" id="show-more-left" disabled></button>
<button type="button" id="show-less-left"></button>
</div>
<div style="float: left; text-align: right; width: 50%">
<button type="button" id="show-less-right"></button>
<button type="button" id="show-more-right" disabled></button>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js"></script>
<script type="module">
import commits from "./benchmark_data.json" with { type: "json" };
// Amend the commits with their unique index.
for (var i = 0; i < commits.length; i++) {
commits[i].index = i;
}
// Utility methods.
Array.prototype.first = function() {
return this[0];
};
Array.prototype.avg = function() {
return this.reduce(function(x, y) { return x + y; }, 0) / this.length;
};
Array.prototype.min = function() {
return this.reduce(function(x, y) { return x === null ? y : Math.min(x, y); }, null);
};
// DOM references.
const benchmarkSelector = document.getElementById('benchmark-selector')
const canvas = document.getElementById('myChart');
const showMoreLeft = document.getElementById('show-more-left');
const showLessLeft = document.getElementById('show-less-left');
const showLessRight = document.getElementById('show-less-right');
const showMoreRight = document.getElementById('show-more-right');
// Initialize benchmark selector.
const benchmarks = new Set();
for (const commit of commits.values()) {
for (const benchmark in commit.benchmarks) {
benchmarks.add(benchmark)
}
}
var selectedBenchmark = window.location.hash.substring(1)
if (!benchmarks.has(selectedBenchmark)) {
selectedBenchmark = benchmarks.values().next().value;
}
for (const benchmark of benchmarks.values()) {
const opt = document.createElement('option');
opt.value = benchmark;
opt.innerHTML = benchmark;
benchmarkSelector.appendChild(opt);
if (benchmark == selectedBenchmark) {
benchmarkSelector.selectedIndex = benchmarkSelector.options.length - 1
}
}
benchmarkSelector.onchange = function(event) {
selectedBenchmark =
benchmarkSelector.options[benchmarkSelector.selectedIndex].value;
updateChart();
window.location.hash = selectedBenchmark;
};
// Chart data provider.
function getData(start = 0, end = commits.length) {
const filteredCommits =
commits
.slice(start, end)
.filter(
commit =>
selectedBenchmark in commit.benchmarks
&& commit.benchmarks[selectedBenchmark].results.length > 0);
const labels = filteredCommits.map((c, i) => c.index);
const codeSizeData =
filteredCommits.map(
(c, i) =>
filteredCommits[i]
.benchmarks[selectedBenchmark]
.results
.first()
.code_size);
const runtimeData =
filteredCommits.map(
(c, i) =>
filteredCommits[i]
.benchmarks[selectedBenchmark]
.results
.map(result => result.runtime)
.min());
const runtimeScatterData = [];
for (const commit of filteredCommits.values()) {
const runtimes =
commit.benchmarks[selectedBenchmark].results.map(result => result.runtime)
for (const runtime of runtimes.values()) {
runtimeScatterData.push({ x: commit.index, y: runtime });
}
}
return {
labels: labels,
datasets: [{
type: 'line',
label: 'Code size',
data: codeSizeData,
tension: 0.1
},
{
type: 'line',
label: 'Runtime',
data: runtimeData,
tension: 0.1,
yAxisID: 'y2'
},
{
type: 'scatter',
label: 'Runtime',
data: runtimeScatterData,
yAxisID: 'y2'
}
],
};
}
// Chart options.
const options = {
onHover: (event, chartElement) =>
event.native.target.style.cursor =
chartElement[0] ? 'pointer' : 'default',
plugins: {
tooltip: {
callbacks: {
title: (context) => {
const elementInfo = context[0];
var commit;
if (elementInfo.dataset.type == 'line') {
commit = commits[elementInfo.dataIndex];
} else {
console.assert(elementInfo.dataset.type == 'scatter');
commit = commits[elementInfo.raw.x];
}
return commit.title;
},
footer: (context) => {
const elementInfo = context[0];
var commit;
if (elementInfo.dataset.type == 'line') {
commit = commits[elementInfo.dataIndex];
} else {
console.assert(elementInfo.dataset.type == 'scatter');
commit = commits[elementInfo.raw.x];
}
return `Author: ${commit.author}\n`
+ `Submitted: ${commit.submitted}\n`
+ `Hash: ${commit.hash}`;
}
}
}
},
responsive: true,
scales: {
x: {},
y: {
position: 'left',
title: {
display: true,
text: 'Code size (bytes)'
}
},
y2: {
position: 'right',
title: {
display: true,
text: 'Runtime (ms)'
}
}
}
};
// Create chart.
const myChart = new Chart(canvas, {
data: getData(),
options: options
});
// Setup click handler.
canvas.onclick = function (event) {
const points =
myChart.getElementsAtEventForMode(
event, 'nearest', { intersect: true }, true);
if (points.length > 0) {
const point = points[0];
const commit = commits[point.index];
window.open('https://r8.googlesource.com/r8/+/' + commit.hash, '_blank');
}
};
// Setup chart navigation.
var left = 0;
var right = commits.length;
showMoreLeft.onclick = function (event) {
if (left == 0) {
return;
}
const currentSize = right - left;
left = left - currentSize;
if (left < 0) {
left = 0;
}
updateChart();
};
showLessLeft.onclick = function (event) {
const currentSize = right - left;
left = left + Math.floor(currentSize / 2);
if (left >= right) {
left = right - 1;
}
updateChart();
};
showLessRight.onclick = function (event) {
if (right == 0) {
return;
}
const currentSize = right - left;
right = right - Math.floor(currentSize / 2);
if (right < left) {
right = left;
}
updateChart();
};
showMoreRight.onclick = function (event) {
const currentSize = right - left;
right = right + currentSize;
if (right > commits.length) {
right = commits.length;
}
updateChart();
};
function updateChart() {
console.assert(left <= right);
const newData = getData(left, right);
Object.assign(myChart.data, newData);
myChart.update();
showMoreLeft.disabled = left == 0;
showLessLeft.disabled = left == right - 1;
showLessRight.disabled = left == right - 1;
showMoreRight.disabled = right == commits.length;
}
</script>
</body>
</html>