1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <title>bench-flame-diff</title>
5  <link rel="preconnect" href="https://fonts.googleapis.com">
6  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
7  <link href="https://fonts.googleapis.com/css2?family=Roboto:300,300italic,700,700italic&display=swap" rel="stylesheet">
8  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" integrity="sha512-NhSC1YmyruXifcj/KFRWoC561YpHpc5Jtzgvbuzx5VozKpWvQ+4nXhPdFgmx8xqexRcpAglTj9sIBWINXa8x5w==" crossorigin="anonymous" referrerpolicy="no-referrer"/>
9  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.min.css" integrity="sha512-xiunq9hpKsIcz42zt0o2vCo34xV0j6Ny8hgEylN3XBglZDtTZ2nwnqF/Z/TTCc18sGdvCjbFInNd++6q3J0N6g==" crossorigin="anonymous" referrerpolicy="no-referrer"/>
10  <style>
11    #row--title-and-help {
12      display: flex;
13      justify-content: space-between;
14      align-items: center;
15    }
16    #row--before-after {
17      display: flex;
18    }
19    #row--before-after > div, #row--before-after > div > div {
20      display: flex;
21      flex-direction: column;
22    }
23    #row--before-after > div {
24      align-items: flex-start;
25      flex-basis: 50%;
26      padding: 5px;
27    }
28    #row--before-after > :first-child {
29      align-items: flex-end;
30    }
31    #row--before-after, #row--graphs {
32      max-width: 1800px;
33    }
34  </style>
35</head>
36<body>
37<!--title and the help button-->
38<header>
39  <div id="row--title-and-help">
40    <h2>bench-flame-diff</h2>
41    <button onclick="window.open('http://go/bench-flame-diff-readme')">help</button>
42  </div>
43</header>
44<main>
45  <!--two column view-->
46  <div id="row--before-after">
47    <!--column-left-->
48    <div>
49      <h3>Before</h3>
50      <div>
51        <button onclick="openTab('%before_raw_name%')">%before_raw_name%</button>
52        <button onclick="openTab('%before_diff_name%')">%before_diff_name%</button>
53      </div>
54      <div id="results-before"></div>
55    </div>
56    <!--column-right-->
57    <div>
58      <h3>After</h3>
59      <div>
60        <button onclick="openTab('%after_raw_name%')">%after_raw_name%</button>
61        <button onclick="openTab('%after_diff_name%')">%after_diff_name%</button>
62      </div>
63      <div id="results-after"></div>
64    </div>
65  </div>
66
67  <!--graphs-->
68  <div id="row--graphs">
69    <div id="%before_raw_name%" class="svg">
70      <object type="image/svg+xml" data="%before_raw_file%">Failed to display the file: %before_raw_file%</object>
71    </div>
72    <div id="%before_diff_name%" class="svg">
73      <object type="image/svg+xml" data="%before_diff_file%">Failed to display the file: %before_diff_file%</object>
74    </div>
75    <div id="%after_raw_name%" class="svg">
76      <object type="image/svg+xml" data="%after_raw_file%">Failed to display the file: %after_raw_file%</object>
77    </div>
78    <div id="%after_diff_name%" class="svg">
79      <object type="image/svg+xml" data="%after_diff_file%">Failed to display the file: %after_diff_file%</object>
80    </div>
81  </div>
82</main>
83
84<!-- Note: 'application/json' ensures the content is treated as data (i.e. not executed) -->
85<script type="application/json" id="result-before-raw">
86  %benchmark_result_before_raw%
87</script>
88
89<script type="application/json" id="result-after-raw">
90  %benchmark_result_after_raw%
91</script>
92
93<script>
94  function openTab(tabName) {
95    let tab = document.getElementsByClassName("svg");
96    for (let i = 0; i < tab.length; i++) tab[i].style.display = "none";
97    document.getElementById(tabName).style.display = "block";
98  }
99
100  function formatNumber(numberRaw) {
101    const intAbs = Math.abs(Math.round(numberRaw))
102    let maxFrac = 2;
103    if (intAbs >= 10) maxFrac = 1;
104    if (intAbs >= 100) maxFrac = 0;
105    const formatter = new Intl.NumberFormat('en-US', {
106      maximumFractionDigits: maxFrac,
107      minimumFractionDigits: 0,
108      useGrouping: true,
109    });
110    return formatter.format(numberRaw);
111  }
112
113  function populateBenchmarkResult(label, dataSourceId, traceFileName) {
114    const dataString = document.getElementById(dataSourceId).textContent.trim()
115    if (!dataString) return // no benchmark result data
116
117    const benchmark = JSON.parse(dataString).benchmarks.find(b =>
118      b.profilerOutputs &&
119      b.profilerOutputs.some(po => po.filename === traceFileName)
120    ) || undefined;
121    if (!benchmark || !benchmark.metrics) return // no benchmark matching the trace file name
122    const metrics = benchmark.metrics;
123    if (Object.keys(metrics).length === 0) return
124
125    let rowData = "";
126    Object.entries(metrics).forEach(([metricName, metricResult],) => {
127      const {minimum, median, maximum} = metricResult;
128      rowData += "<tr>" +
129        `<td>${metricName}</td>` +
130        `<td>${formatNumber(minimum)}</td>` +
131        `<td>${formatNumber(median)}</td>` +
132        `<td>${formatNumber(maximum)}</td>` +
133        "</tr>"
134    })
135    document.querySelector(`#results-${label}`).innerHTML += "<table>" +
136      "<thead>" +
137      "<th>metric</th>" +
138      "<th>min</th>" +
139      "<th>median</th>" +
140      "<th>max</th>" +
141      "</thead>" +
142      "<tbody>" +
143      rowData +
144      "</tbody>" +
145      "</table>"
146  }
147
148  populateBenchmarkResult("before", "result-before-raw", "%before_trace_file_name%")
149  populateBenchmarkResult("after", "result-after-raw", "%after_trace_file_name%")
150  openTab("%after_diff_name%");
151</script>
152</body>
153</html>
154