index.html 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. <body>
  89. <header id="header">
  90. <div class="header-item">
  91. <strong class="header-label">Last Update:</strong>
  92. <span id="last-update"></span>
  93. </div>
  94. <div class="header-item">
  95. <strong class="header-label">Repository:</strong>
  96. <a id="repository-link" rel="noopener"></a>
  97. </div>
  98. </header>
  99. <main id="main"></main>
  100. <footer>
  101. <button id="dl-button">Download data as JSON</button>
  102. <div class="spacer"></div>
  103. <div class="small">Powered by <a rel="noopener" href="https://github.com/marketplace/actions/continuous-benchmark">github-action-benchmark</a></div>
  104. </footer>
  105. <script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.2/dist/Chart.min.js"></script>
  106. <script src="data.js"></script>
  107. <script id="main-script">
  108. 'use strict';
  109. (function() {
  110. // Colors from https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
  111. const toolColors = {
  112. cargo: '#dea584',
  113. go: '#00add8',
  114. benchmarkjs: '#f1e05a',
  115. pytest: '#3572a5',
  116. googlecpp: '#f34b7d',
  117. catch2: '#f34b7d',
  118. julia: '#a270ba',
  119. customBiggerIsBetter: '#38ff38',
  120. customSmallerIsBetter: '#ff3838',
  121. _: '#333333'
  122. };
  123. function init() {
  124. function collectBenchesPerTestCase(entries) {
  125. const map = new Map();
  126. for (const entry of entries) {
  127. const {commit, date, tool, benches} = entry;
  128. for (const bench of benches) {
  129. const result = { commit, date, tool, bench };
  130. const arr = map.get(bench.name);
  131. if (arr === undefined) {
  132. map.set(bench.name, [result]);
  133. } else {
  134. arr.push(result);
  135. }
  136. }
  137. }
  138. return map;
  139. }
  140. const data = window.BENCHMARK_DATA;
  141. // Render header
  142. document.getElementById('last-update').textContent = new Date(data.lastUpdate).toString();
  143. const repoLink = document.getElementById('repository-link');
  144. repoLink.href = data.repoUrl;
  145. repoLink.textContent = data.repoUrl;
  146. // Render footer
  147. document.getElementById('dl-button').onclick = () => {
  148. const dataUrl = 'data:,' + JSON.stringify(data, null, 2);
  149. const a = document.createElement('a');
  150. a.href = dataUrl;
  151. a.download = 'benchmark_data.json';
  152. a.click();
  153. };
  154. // Prepare data points for charts
  155. return Object.keys(data.entries).map(name => ({
  156. name,
  157. dataSet: collectBenchesPerTestCase(data.entries[name]),
  158. }));
  159. }
  160. function renderAllChars(dataSets) {
  161. function renderGraph(parent, name, dataset) {
  162. const canvas = document.createElement('canvas');
  163. canvas.className = 'benchmark-chart';
  164. parent.appendChild(canvas);
  165. const color = toolColors[dataset.length > 0 ? dataset[0].tool : '_'];
  166. const data = {
  167. labels: dataset.map(d => d.commit.id.slice(0, 7)),
  168. datasets: [
  169. {
  170. label: name,
  171. data: dataset.map(d => d.bench.value),
  172. borderColor: color,
  173. backgroundColor: color + '60', // Add alpha for #rrggbbaa
  174. }
  175. ],
  176. };
  177. const options = {
  178. scales: {
  179. xAxes: [
  180. {
  181. scaleLabel: {
  182. display: true,
  183. labelString: 'commit',
  184. },
  185. }
  186. ],
  187. yAxes: [
  188. {
  189. scaleLabel: {
  190. display: true,
  191. labelString: dataset.length > 0 ? dataset[0].bench.unit : '',
  192. },
  193. ticks: {
  194. beginAtZero: true,
  195. }
  196. }
  197. ],
  198. },
  199. tooltips: {
  200. callbacks: {
  201. afterTitle: items => {
  202. const {index} = items[0];
  203. const data = dataset[index];
  204. return '\n' + data.commit.message + '\n\n' + data.commit.timestamp + ' committed by @' + data.commit.committer.username + '\n';
  205. },
  206. label: item => {
  207. let label = item.value;
  208. const { range, unit } = dataset[item.index].bench;
  209. label += ' ' + unit;
  210. if (range) {
  211. label += ' (' + range + ')';
  212. }
  213. return label;
  214. },
  215. afterLabel: item => {
  216. const { extra } = dataset[item.index].bench;
  217. return extra ? '\n' + extra : '';
  218. }
  219. }
  220. },
  221. onClick: (_mouseEvent, activeElems) => {
  222. if (activeElems.length === 0) {
  223. return;
  224. }
  225. // XXX: Undocumented. How can we know the index?
  226. const index = activeElems[0]._index;
  227. const url = dataset[index].commit.url;
  228. window.open(url, '_blank');
  229. },
  230. };
  231. new Chart(canvas, {
  232. type: 'line',
  233. data,
  234. options,
  235. });
  236. }
  237. function renderBenchSet(name, benchSet, main) {
  238. const setElem = document.createElement('div');
  239. setElem.className = 'benchmark-set';
  240. main.appendChild(setElem);
  241. const nameElem = document.createElement('h1');
  242. nameElem.className = 'benchmark-title';
  243. nameElem.textContent = name;
  244. setElem.appendChild(nameElem);
  245. const graphsElem = document.createElement('div');
  246. graphsElem.className = 'benchmark-graphs';
  247. setElem.appendChild(graphsElem);
  248. for (const [benchName, benches] of benchSet.entries()) {
  249. renderGraph(graphsElem, benchName, benches)
  250. }
  251. }
  252. const main = document.getElementById('main');
  253. for (const {name, dataSet} of dataSets) {
  254. renderBenchSet(name, dataSet, main);
  255. }
  256. }
  257. renderAllChars(init()); // Start
  258. })();
  259. </script>
  260. </body>
  261. </html>