1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes" />
6 <style>
7 html {
8 font-family: BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
9 -webkit-font-smoothing: antialiased;
10 background-color: #fff;
11 font-size: 16px;
12 }
13 body {
14 color: #4a4a4a;
15 margin: 8px;
16 font-size: 1em;
17 font-weight: 400;
18 }
19 header {
20 margin-bottom: 8px;
21 display: flex;
22 flex-direction: column;
23 }
24 main {
25 width: 100%;
26 display: flex;
27 flex-direction: column;
28 }
29 a {
30 color: #3273dc;
31 cursor: pointer;
32 text-decoration: none;
33 }
34 a:hover {
35 color: #000;
36 }
37 button {
38 color: #fff;
39 background-color: #3298dc;
40 border-color: transparent;
41 cursor: pointer;
42 text-align: center;
43 }
44 button:hover {
45 background-color: #2793da;
46 flex: none;
47 }
48 .spacer {
49 flex: auto;
50 }
51 .small {
52 font-size: 0.75rem;
53 }
54 footer {
55 margin-top: 16px;
56 display: flex;
57 align-items: center;
58 }
59 .header-label {
60 margin-right: 4px;
61 }
62 .benchmark-set {
63 margin: 8px 0;
64 width: 100%;
65 display: flex;
66 flex-direction: column;
67 }
68 .benchmark-title {
69 font-size: 3rem;
70 font-weight: 600;
71 word-break: break-word;
72 text-align: center;
73 }
74 .benchmark-graphs {
75 display: flex;
76 flex-direction: row;
77 justify-content: space-around;
78 align-items: center;
79 flex-wrap: wrap;
80 width: 100%;
81 }
82 .benchmark-chart {
83 max-width: 1000px;
84 }
85 </style>
86 <title>Benchmarks</title>
87 </head>
88
89 <body>
90 <header id="header">
91 <div class="header-item">
92 <strong class="header-label">Last Update:</strong>
93 <span id="last-update"></span>
94 </div>
95 <div class="header-item">
96 <strong class="header-label">Repository:</strong>
97 <a id="repository-link" rel="noopener"></a>
98 </div>
99 </header>
100 <main id="main"></main>
101 <footer>
102 <button id="dl-button">Download data as JSON</button>
103 <div class="spacer"></div>
104 <div class="small">Powered by <a rel="noopener" href="https://github.com/marketplace/actions/continuous-benchmark">github-action-benchmark</a></div>
105 </footer>
106
107 <script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.2/dist/Chart.min.js"></script>
108 <script src="data.js"></script>
109 <script id="main-script">
110 'use strict';
111 (function() {
112 // Colors from https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
113 const toolColors = {
114 cargo: '#dea584',
115 go: '#00add8',
116 benchmarkjs: '#f1e05a',
117 benchmarkluau: '#000080',
118 pytest: '#3572a5',
119 googlecpp: '#f34b7d',
120 catch2: '#f34b7d',
121 julia: '#a270ba',
122 jmh: '#b07219',
123 benchmarkdotnet: '#178600',
124 customBiggerIsBetter: '#38ff38',
125 customSmallerIsBetter: '#ff3838',
126 _: '#333333'
127 };
128
129 function init() {
130 function collectBenchesPerTestCase(entries) {
131 const map = new Map();
132 for (const entry of entries) {
133 const {commit, date, tool, benches} = entry;
134 for (const bench of benches) {
135 const result = { commit, date, tool, bench };
136 const arr = map.get(bench.name);
137 if (arr === undefined) {
138 map.set(bench.name, [result]);
139 } else {
140 arr.push(result);
141 }
142 }
143 }
144 return map;
145 }
146
147 const data = window.BENCHMARK_DATA;
148
149 // Render header
150 document.getElementById('last-update').textContent = new Date(data.lastUpdate).toString();
151 const repoLink = document.getElementById('repository-link');
152 repoLink.href = data.repoUrl;
153 repoLink.textContent = data.repoUrl;
154
155 // Render footer
156 document.getElementById('dl-button').onclick = () => {
157 const dataUrl = 'data:,' + JSON.stringify(data, null, 2);
158 const a = document.createElement('a');
159 a.href = dataUrl;
160 a.download = 'benchmark_data.json';
161 a.click();
162 };
163
164 // Prepare data points for charts
165 return Object.keys(data.entries).map(name => ({
166 name,
167 dataSet: collectBenchesPerTestCase(data.entries[name]),
168 }));
169 }
170
171 function renderAllChars(dataSets) {
172
173 function renderGraph(parent, name, dataset) {
174 const canvas = document.createElement('canvas');
175 canvas.className = 'benchmark-chart';
176 parent.appendChild(canvas);
177
178 const color = toolColors[dataset.length > 0 ? dataset[0].tool : '_'];
179 const data = {
180 labels: dataset.map(d => d.commit.id.slice(0, 7)),
181 datasets: [
182 {
183 label: name,
184 data: dataset.map(d => d.bench.value),
185 borderColor: color,
186 backgroundColor: color + '60', // Add alpha for #rrggbbaa
187 }
188 ],
189 };
190 const options = {
191 scales: {
192 xAxes: [
193 {
194 scaleLabel: {
195 display: true,
196 labelString: 'commit',
197 },
198 }
199 ],
200 yAxes: [
201 {
202 scaleLabel: {
203 display: true,
204 labelString: dataset.length > 0 ? dataset[0].bench.unit : '',
205 },
206 ticks: {
207 beginAtZero: true,
208 }
209 }
210 ],
211 },
212 tooltips: {
213 callbacks: {
214 afterTitle: items => {
215 const {index} = items[0];
216 const data = dataset[index];
217 return '\n' + data.commit.message + '\n\n' + data.commit.timestamp + ' committed by @' + data.commit.committer.username + '\n';
218 },
219 label: item => {
220 let label = item.value;
221 const { range, unit } = dataset[item.index].bench;
222 label += ' ' + unit;
223 if (range) {
224 label += ' (' + range + ')';
225 }
226 return label;
227 },
228 afterLabel: item => {
229 const { extra } = dataset[item.index].bench;
230 return extra ? '\n' + extra : '';
231 }
232 }
233 },
234 onClick: (_mouseEvent, activeElems) => {
235 if (activeElems.length === 0) {
236 return;
237 }
238 // XXX: Undocumented. How can we know the index?
239 const index = activeElems[0]._index;
240 const url = dataset[index].commit.url;
241 window.open(url, '_blank');
242 },
243 };
244
245 new Chart(canvas, {
246 type: 'line',
247 data,
248 options,
249 });
250 }
251
252 function renderBenchSet(name, benchSet, main) {
253 const setElem = document.createElement('div');
254 setElem.className = 'benchmark-set';
255 main.appendChild(setElem);
256
257 const nameElem = document.createElement('h1');
258 nameElem.className = 'benchmark-title';
259 nameElem.textContent = name;
260 setElem.appendChild(nameElem);
261
262 const graphsElem = document.createElement('div');
263 graphsElem.className = 'benchmark-graphs';
264 setElem.appendChild(graphsElem);
265
266 for (const [benchName, benches] of benchSet.entries()) {
267 renderGraph(graphsElem, benchName, benches)
268 }
269 }
270
271 const main = document.getElementById('main');
272 for (const {name, dataSet} of dataSets) {
273 renderBenchSet(name, dataSet, main);
274 }
275 }
276
277 renderAllChars(init()); // Start
278 })();
279 </script>
280 </body>
281</html>