--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ var platform = 'windows10-64-shippable-qr';
+
+ const searchParams = new URLSearchParams(window.location.search);
+
+ let likelyDataURL = 'https://sql.telemetry.mozilla.org/api/queries/92092/results.json?api_key=MaQkSpIR19BM4Jr5QPKt7nDZpkjEPmmGc2cEtpiW';
+ let timeWindow = '6wk';
+
+ if (searchParams.get('os') == 'osx') {
+ platform = 'macosx1015-64-shippable-qr';
+ } else if (searchParams.get('os') == 'linux') {
+ platform = 'linux1804-64-shippable-qr';
+ } else if (searchParams.get('os') == 'android') {
+ platform = 'android-hw-a51-11-0-aarch64-shippable-qr';
+ }
+
+ fetch(likelyDataURL)
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ loadDataLikely(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+
+ function getDiffColor(diff) {
+ if (diff > 0.05) {
+ return 'green'
+ } else if (diff > -0.095) {
+ return 'black'
+ } else if (diff > -0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function getSelfDiffColor(diff) {
+ if (diff > 1.02) {
+ return 'green';
+ } else if (diff < 0.98) {
+ return 'red';
+ } else {
+ return 'black';
+ }
+ }
+
+ function fillData(tableId, row) {
+ if (row.platform != platform) {
+ return;
+ }
+ diffColor = getDiffColor(row.Difference);
+ oldDiffColor = getDiffColor(row.OldDifference);
+
+ let firefoxDiff = 1.0;
+ if (row.FirefoxOldMean > 0) {
+ firefoxDiff = row.FirefoxDifference;
+ }
+
+ document.getElementById(tableId).innerHTML += '<tr onClick="openTestComparison(' + row.signature_id_firefox + ', ' + row.signature_id_chrome + ');"><th scope="row" class="testName">' +
+ row.test.split('/')[0] + '</th><td>' +
+ round(row.FirefoxMean, 2) + ' runs/s</td><td>' +
+ round(row.ChromeMean, 2) + ' runs/s</td><td style=\'color: ' + diffColor + '\'>' +
+ Math.round(-row.Difference * 100) + '\%</td><td>' +
+ round(row.FirefoxOldMean, 2) + ' runs/s</td><td>' +
+ round(row.ChromeOldMean, 2) + ' runs/s</td><td style=\'color: ' + oldDiffColor + '\'>' +
+ Math.round(-row.OldDifference * 100) + '\%</td><td style=\'color: ' + getSelfDiffColor(firefoxDiff) + '\'>' +
+ Math.round(-(1 - firefoxDiff) * 100) + '%</td></tr >\n';
+ }
+ function loadDataLikely(data) {
+ data.query_result.data.rows.forEach(fillData.bind(null, 'tableBodyLikely'));
+
+ document.getElementById('timewindow').innerHTML = timeWindow + ' prior';
+
+ let arithmeticMeanOfLogsFX = 0;
+ let arithmeticMeanOfLogsFXOld = 0;
+ let arithmeticMeanOfLogsChrome = 0;
+ let arithmeticMeanOfLogsChromeOld = 0;
+ let numValues = 0;
+ let numValuesOld = 0;
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != platform) {
+ return;
+ }
+ numValues++;
+ arithmeticMeanOfLogsFX += Math.log(row.FirefoxMean);
+ arithmeticMeanOfLogsChrome += Math.log(row.ChromeMean);
+ if (row.FirefoxOldMean > 0) {
+ numValuesOld++;
+ arithmeticMeanOfLogsFXOld += Math.log(row.FirefoxOldMean);
+ arithmeticMeanOfLogsChromeOld += Math.log(row.ChromeOldMean);
+ }
+ });
+ let FxGeoMean = Math.exp(arithmeticMeanOfLogsFX / numValues);
+ let ChromeGeoMean = Math.exp(arithmeticMeanOfLogsChrome / numValues);
+ let FxOldGeoMean = Math.exp(arithmeticMeanOfLogsFXOld / numValuesOld);
+ let ChromeOldGeoMean = Math.exp(arithmeticMeanOfLogsChromeOld / numValuesOld);
+
+ let diff = FxGeoMean / ChromeGeoMean - 1;
+ let oldDiff = ChromeOldGeoMean > 0 ? (FxOldGeoMean / ChromeOldGeoMean - 1) : 0;
+ let diffColor = getDiffColor(diff);
+ let oldDiffColor = getDiffColor(oldDiff);
+ let firefoxDiff = 0;
+ if (FxOldGeoMean > 0) {
+ firefoxDiff = FxGeoMean / FxOldGeoMean;
+ }
+
+ document.getElementById("tableBodyLikely").innerHTML += '<tr class="sumRow"><th scope="row" class="testName">Total Score</th><td>' +
+ round(FxGeoMean, 2) + ' runs/s</td><td>' +
+ round(ChromeGeoMean, 2) + ' runs/s</td><td style=\'color: ' + diffColor + '\'>' +
+ round(-diff * 100, 2) + '\%</td><td>' +
+ round(FxOldGeoMean, 2) + ' runs/s</td><td>' +
+ round(ChromeOldGeoMean, 2) + ' runs/s</td><td style=\'color: ' + oldDiffColor + '\'>' +
+ round(-oldDiff * 100, 2) + '\%</td><td style=\'color: ' + getSelfDiffColor(firefoxDiff) + '\'>' +
+ Math.round(-(1 - firefoxDiff) * 100) + '%</td></tr >\n';
+ }
+
+ function openTestComparison(signatureFirefox, signatureChrome) {
+ let repoFirefox = 'mozilla-central';
+ let repoChrome = 'mozilla-central';
+ if (platform == 'android-hw-a51-11-0-aarch64-shippable-qr') {
+ repoFirefox = 'firefox-android';
+ }
+ window.open("https://treeherder.mozilla.org/perfherder/graphs?highlightAlerts=1&highlightChangelogData=1&highlightCommonAlerts=0&series=" + repoFirefox + "," + signatureFirefox + ",1,13&series=" + repoChrome + "," + signatureChrome + ",1,13&timerange=7776000", "_blank")
+ }
+
+ function loadChart() {
+ if (searchParams.get('os') == 'osx') {
+ document.getElementById("macbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'linux') {
+ document.getElementById("linuxbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'android') {
+ document.getElementById("mobilebutton").style.backgroundColor = "gray";
+ } else {
+ document.getElementById("windowsbutton").style = "background-color:gray;";
+ }
+ fetch('https://sql.telemetry.mozilla.org/api/queries/89971/results.json?api_key=6cd9JzffuVjIytWO8fuXs33HXKRjiy9bHJmHfndj')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayChart(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ }
+
+ function displayChart(data) {
+ const ctx = document.getElementById('myChart').getContext('2d');
+ let xyValuesFx = [];
+ let xyValuesChrome = [];
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != platform) {
+ return;
+ }
+ // Hack to remove values where a run failed.
+ if (row.application == 'firefox' && row.geomean > 300) {
+ return;
+ }
+ if (row.application == 'firefox' || row.application == 'fenix') { xyValuesFx.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'chrome' || row.application == 'chrome-m') { xyValuesChrome.push({ x: row.push_timestamp, y: row.geomean }); }
+ });
+
+ let cfg = {
+ type: "scatter",
+ data: {
+ datasets: [
+ {
+ label: 'Firefox',
+ pointRadius: 4,
+ pointBackgroundColor: "#FF9500",
+ data: xyValuesFx
+ },
+ {
+ label: 'Chrome',
+ pointRadius: 4,
+ pointBackgroundColor: "#1DA462",
+ data: xyValuesChrome
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 2,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ }
+ },
+ y: {
+ beginAtZero: true
+ }
+ },
+ plugins: {
+ annotation: {
+ annotations: {
+ line1: {
+ type: 'line',
+ xMin: '2023-03-01 03:56',
+ xMax: '2023-03-01 03:56',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label1: {
+ type: 'label',
+ xValue: '2023-03-01 03:56',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 300 : 50,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['React-Stockcharts Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line2: {
+ type: 'line',
+ xMin: '2023-03-15 08:00',
+ xMax: '2023-03-15 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label2: {
+ type: 'label',
+ xValue: '2023-03-15 08:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 300 : 50,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Editor Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line3: {
+ type: 'line',
+ xMin: '2023-03-29 08:00',
+ xMax: '2023-03-29 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label3: {
+ type: 'label',
+ xValue: '2023-03-29 08:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Frameworks Updated'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line4: {
+ type: 'line',
+ xMin: '2023-04-14 08:00',
+ xMax: '2023-04-14 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label4: {
+ type: 'label',
+ xValue: '2023-04-14 08:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Svelte Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ }
+ }
+ }
+ }
+ }
+ };
+
+ if (platform == 'linux1804-64-shippable-qr') {
+ cfg.options.plugins.annotation.annotations.line3 = {
+ type: 'line',
+ xMin: '2023-02-08 17:00',
+ xMax: '2023-02-08 17:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ };
+ cfg.options.plugins.annotation.annotations.label3 = {
+ type: 'label',
+ xValue: '2023-02-08 17:00',
+ yValue: 50,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Linux Firmware Update'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ };
+ }
+
+ let myChart = new Chart("myChart", cfg);
+ }
+
+ </script>
+ <style>
+ h3 {
+ font-family: sans-serif;
+ }
+
+ .styled-table {
+ border-collapse: collapse;
+ margin: 25px 0;
+ font-size: 0.9em;
+ font-family: sans-serif;
+ min-width: 400px;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .styled-table thead th {
+ background-color: #3366ff;
+ color: #ffffff;
+ text-align: center;
+ }
+
+ .styled-table th {
+ padding: 12px 15px;
+ }
+
+ .styled-table td {
+ text-align: right;
+ }
+
+ .styled-table .testName {
+ text-align: right;
+ }
+
+ .tableBody tr {
+ border-bottom: 1px solid #dddddd;
+ }
+
+ .tableBody .sumRow {
+ border-top: 2px solid black;
+ }
+
+ .tableBody tr:nth-of-type(odd) {
+ background-color: #f3f3f3;
+ }
+
+ .tableBody tr:nth-of-type(even) {
+ background-color: #e3e3e3;
+ }
+
+ .tableBody tr:hover {
+ background-color: #d0d0d0;
+ }
+
+ .buttons td {
+ width: 200px;
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 20px;
+ }
+
+ a {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ text-decoration: none;
+ color: black;
+ border-radius: 5px;
+ }
+
+ a:hover {
+ background-color: lightgray;
+ }
+ </style>
+</head>
+
+<body>
+ <center>
+ <table class="buttons">
+ <tr><td><a href="details-jetstream.html" id="windowsbutton">Windows</a></td><td><a href="details-jetstream.html?os=osx" id="macbutton">Mac OSX</a></td><td><a href="details-jetstream.html?os=linux" id="linuxbutton">Linux</a></td></tr>
+ <tr><td colspan="3" style="height:80px;"><a href="details-jetstream.html?os=android" id="mobilebutton">Android</a></td></tr>
+ </table>
+
+ <h3>Breakdown: Jetsream 2 Likely Candidates</h3>
+ <table class="styled-table">
+ <col>
+ <col>
+ <colgroup span="2"></colgroup>
+ <col>
+ <colgroup span="2"></colgroup>
+ <col>
+ <thead>
+ <tr><th rowspan="2"></th><th colspan="2" scope="colgroup">Total time (Higher is better)<br />1wk moving average</th><th rowspan="2">Difference</th><th colspan="2" scope="colgroup" id="timewindow">6wk prior</th><th rowspan="2">Difference</th><th rowspan="2">Firefox<br />Evolution</th></tr>
+ <tr><th scope="col">Firefox<br />Nightly</th><th scope="col">Chrome<br />Release</th><th scope="col">Firefox<br />Nightly</th><th scope="col">Chrome<br />Release</th></tr>
+ </thead>
+ <tbody class="tableBody" id="tableBodyLikely">
+ </tbody>
+ </table>
+ </center>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ var platform = 'windows10-64-shippable-qr';
+
+ const searchParams = new URLSearchParams(window.location.search);
+
+ let likelyDataURL = 'https://sql.telemetry.mozilla.org/api/queries/97531/results.json?api_key=IaOu0H5GXoCdMzhxudfQOMVVv66WgD1cfWpRYxk5';
+ let timeWindow = '6wk';
+ let supportsCaR = true;
+
+ let range = '';
+
+ var timeChart;
+
+ if (searchParams.get('os') == 'osx') {
+ platform = 'macosx1015-64-shippable-qr';
+ } else if (searchParams.get('os') == 'osxm2') {
+ platform = 'macosx1300-64-shippable-qr';
+ } else if (searchParams.get('os') == 'linux') {
+ platform = 'linux1804-64-shippable-qr';
+ } else if (searchParams.get('os') == 'android') {
+ platform = 'android-hw-a51-11-0-aarch64-shippable-qr';
+ }
+
+ fetch(likelyDataURL)
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ loadDataLikely(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+
+ function getDiffColor(diff) {
+ if (diff < -0.05) {
+ return 'green'
+ } else if (diff < 0.095) {
+ return 'black'
+ } else if (diff < 0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function getSelfDiffColor(diff) {
+ if (diff <= 0.98) {
+ return 'green';
+ } else if (diff >= 1.02) {
+ return 'red';
+ } else {
+ return 'black';
+ }
+ }
+
+ function fillData(tableId, row) {
+ if (row.platform != platform) {
+ return;
+ }
+ diffColor = getDiffColor(row.Difference);
+ oldDiffColor = getDiffColor(row.OldDifference);
+
+ let firefoxDiff = 1.0;
+ if (row.FirefoxOldMean > 0) {
+ firefoxDiff = row.FirefoxDifference;
+ }
+
+
+ let newLine = '';
+ newLine += '<tr onClick="openTestComparison(' + row.signature_id_firefox + ', ' + row.signature_id_chrome + ', ' + row.signature_id_car + ');"><th scope="row" class="testName">' +
+ row.test.split('/')[0] + '</th><td>' +
+ round(row.FirefoxMean, 2) + ' ms</td><td>' +
+ round(row.ChromeMean, 2) + ' ms</td>';
+ if (supportsCaR) {
+ newLine += '<td>' + round(row.CaRMean, 2) + ' ms</td>';
+ }
+ newLine += '<td style =\'color: ' + diffColor + '\'>' +
+ Math.round(-row.Difference * 100) + '\%</td>'
+ if (supportsCaR) {
+ newLine += '<td style=\'color: ' + getDiffColor(row.CaRDifference) + '\'>' + Math.round(-row.CaRDifference * 100) + '\%</td>'
+ }
+ newLine += '<td>' +
+ round(row.FirefoxOldMean, 2) + ' ms</td><td>' +
+ round(row.ChromeOldMean, 2) + ' ms</td><td style=\'color: ' + oldDiffColor + '\'>' +
+ Math.round(-row.OldDifference * 100) + '\%</td><td style=\'color: ' + getSelfDiffColor(firefoxDiff) + '\'>' +
+ Math.round(-(1 - firefoxDiff) * 100) + '%</td></tr >\n';
+
+ document.getElementById(tableId).innerHTML += newLine;
+ }
+
+ function loadDataLikely(data) {
+ let table = document.getElementById('tableLikely');
+ if (!supportsCaR) {
+ table.rows[0].cells[1].colSpan = 2;
+ table.rows[0].cells[2].colSpan = 1;
+ table.rows[1].deleteCell(2);
+ table.rows[1].deleteCell(3);
+ }
+ data.query_result.data.rows.forEach(fillData.bind(null, 'tableBodyLikely'));
+
+ document.getElementById('timewindow').innerHTML = timeWindow + ' prior';
+
+ let arithmeticMeanOfLogsFX = 0;
+ let arithmeticMeanOfLogsFXOld = 0;
+ let arithmeticMeanOfLogsChrome = 0;
+ let arithmeticMeanOfLogsChromeOld = 0;
+ let arithmeticMeanOfLogsCaR = 0;
+ let numValues = 0;
+ let numValuesOld = 0;
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != platform) {
+ return;
+ }
+ numValues++;
+ arithmeticMeanOfLogsFX += Math.log(row.FirefoxMean);
+ arithmeticMeanOfLogsChrome += Math.log(row.ChromeMean);
+ arithmeticMeanOfLogsCaR += Math.log(row.CaRMean);
+ if (row.FirefoxOldMean > 0) {
+ numValuesOld++;
+ arithmeticMeanOfLogsFXOld += Math.log(row.FirefoxOldMean);
+ arithmeticMeanOfLogsChromeOld += Math.log(row.ChromeOldMean);
+ }
+ });
+ let FxGeoMean = Math.exp(arithmeticMeanOfLogsFX / numValues);
+ let ChromeGeoMean = Math.exp(arithmeticMeanOfLogsChrome / numValues);
+ let CaRGeoMean = Math.exp(arithmeticMeanOfLogsCaR / numValues);
+ let FxOldGeoMean = Math.exp(arithmeticMeanOfLogsFXOld / numValuesOld);
+ let ChromeOldGeoMean = Math.exp(arithmeticMeanOfLogsChromeOld / numValuesOld);
+
+ let diff = FxGeoMean / ChromeGeoMean - 1;
+ let CaRdiff = FxGeoMean / CaRGeoMean - 1;
+ let oldDiff = ChromeOldGeoMean > 0 ? (FxOldGeoMean / ChromeOldGeoMean - 1) : 0;
+ let diffColor = getDiffColor(diff);
+ let oldDiffColor = getDiffColor(oldDiff);
+ let firefoxDiff = 0;
+ if (FxOldGeoMean > 0) {
+ firefoxDiff = FxGeoMean / FxOldGeoMean;
+ }
+
+ let newLine = '<tr class="sumRow"><th scope="row" class="testName">Total Score</th><td>' +
+ round(FxGeoMean, 2) + ' ms</td><td>' +
+ round(ChromeGeoMean, 2) + ' ms</td>';
+
+ if (supportsCaR) {
+ newLine += '<td>' +
+ round(CaRGeoMean, 2) + ' ms</td>';
+ }
+
+ newLine += '<td style=\'color: ' + diffColor + '\'>' +
+ round(-diff * 100, 2) + '\%</td>';
+ if (supportsCaR) {
+ newLine += '<td style=\'color: ' + getDiffColor(CaRdiff) + '\'>' +
+ round(-CaRdiff * 100, 2) + '\%</td>';
+ }
+ newLine += '<td>' +
+ round(FxOldGeoMean, 2) + ' ms</td><td>' +
+ round(ChromeOldGeoMean, 2) + ' ms</td><td style=\'color: ' + oldDiffColor + '\'>' +
+ round(-oldDiff * 100, 2) + '\%</td><td style=\'color: ' + getSelfDiffColor(firefoxDiff) + '\'>' +
+ Math.round(-(1 - firefoxDiff) * 100) + '%</td></tr >\n';
+
+ document.getElementById("tableBodyLikely").innerHTML += newLine;
+ }
+
+ function openTestComparison(signatureFirefox, signatureChrome, signatureCaR) {
+ let repoFirefox = 'mozilla-central';
+ let repoChrome = 'mozilla-central';
+ if (platform == 'android-hw-a51-11-0-aarch64-shippable-qr') {
+ repoFirefox = 'firefox-android';
+ }
+ let linkString = "https://treeherder.mozilla.org/perfherder/graphs?highlightAlerts=1&highlightChangelogData=1&highlightCommonAlerts=0&series=" + repoFirefox + "," + signatureFirefox + ",1,13&series=" + repoChrome + "," + signatureChrome + ",1,13&timerange=7776000";
+ if (supportsCaR) {
+ linkString += "&series=" + repoChrome + "," + signatureCaR + ",1,13";
+ }
+ window.open(linkString, "_blank")
+ }
+
+ function loadChart() {
+ if (searchParams.get('os') == 'osx') {
+ document.getElementById("macbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'linux') {
+ document.getElementById("linuxbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'android') {
+ document.getElementById("mobilebutton").style.backgroundColor = "gray";
+ } else if (searchParams.get('os') == 'osxm2') {
+ document.getElementById("osxm2button").style.backgroundColor = "gray";
+ } else {
+ document.getElementById("windowsbutton").style = "background-color:gray;";
+ }
+ fetch('https://sql.telemetry.mozilla.org/api/queries/97533/results.json?api_key=bf25Y5w6XgKXFcG33m3Ce9CIvdO9tT8wOros4NE0')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayChart(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ }
+
+ function displayChart(data) {
+ const ctx = document.getElementById('myChart').getContext('2d');
+ let xyValuesFx = [];
+ let xyValuesChrome = [];
+ let xyValuesCaR = [];
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != platform) {
+ return;
+ }
+ // Hack to remove values where a run failed.
+ if (row.application == 'firefox' && row.geomean > 300) {
+ return;
+ }
+
+ if (row.platform == 'macosx1300-64-shippable-qr' && row.application == 'chrome' && new Date(row.push_timestamp) < new Date('2024-01-24 00:00')) {
+ return;
+ }
+
+ if (row.application == 'firefox' || row.application == 'fenix') { xyValuesFx.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'chrome' || row.application == 'chrome-m') { xyValuesChrome.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'custom-car' || row.application == 'cstm-car-m') { xyValuesCaR.push({ x: row.push_timestamp, y: row.geomean }); }
+ });
+
+ let cfg = {
+ type: "scatter",
+ data: {
+ datasets: [
+ {
+ label: 'Firefox',
+ pointRadius: 3,
+ pointBackgroundColor: "#FF9500",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesFx
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 1.5,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ }
+ },
+ y: {
+ beginAtZero: true
+ }
+ },
+ plugins: {
+ annotation: {
+ annotations: {
+ }
+ }
+ }
+ }
+ };
+
+ cfg.data.datasets.push({
+ label: 'Chrome',
+ pointRadius: 3,
+ pointBackgroundColor: "#1DA462",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesChrome
+ });
+
+ if (platform == 'linux1804-64-shippable-qr') {
+ cfg.options.plugins.annotation.annotations.line3 = {
+ type: 'line',
+ xMin: '2023-02-08 17:00',
+ xMax: '2023-02-08 17:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ };
+ cfg.options.plugins.annotation.annotations.label3 = {
+ type: 'label',
+ xValue: '2023-02-08 17:00',
+ yValue: 50,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Linux Firmware Update'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ };
+ }
+
+ if (xyValuesCaR.length > 0) {
+ cfg.data.datasets.push({
+ label: 'Chromium-as-Release',
+ pointRadius: 3,
+ pointBackgroundColor: "#0099ff",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesCaR
+ });
+ }
+
+ if (platform == 'macosx1300-64-shippable-qr') {
+ cfg.options.scales.x.min = '2023-12-01';
+ }
+
+ timeChart = new Chart("myChart", cfg);
+ }
+
+ function changeRange(newRange) {
+ if (newRange == 'all') {
+ if (platform != 'macosx1300-64-shippable-qr') {
+ timeChart.options.scales.x.min = '';
+ } else {
+ timeChart.options.scales.x.min = '2023-12-01';
+ }
+ } else {
+ var d = new Date();
+ d.setMonth(d.getMonth() - newRange);
+ timeChart.options.scales.x.min = d;
+ }
+ timeChart.update();
+ }
+
+ </script>
+ <style>
+ h3 {
+ font-family: sans-serif;
+ }
+
+ .styled-table {
+ border-collapse: collapse;
+ margin: 25px 0;
+ font-size: 0.9em;
+ font-family: sans-serif;
+ min-width: 400px;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .styled-table thead th {
+ background-color: #3366ff;
+ color: #ffffff;
+ text-align: center;
+ }
+
+ .styled-table th {
+ padding: 12px 15px;
+ }
+
+ .styled-table td {
+ text-align: right;
+ }
+
+ .styled-table .testName {
+ text-align: left;
+ }
+
+ .tableBody tr {
+ border-bottom: 1px solid #dddddd;
+ }
+
+ .tableBody .sumRow {
+ border-top: 2px solid black;
+ }
+
+ .tableBody tr:nth-of-type(odd) {
+ background-color: #f3f3f3;
+ }
+
+ .tableBody tr:nth-of-type(even) {
+ background-color: #e3e3e3;
+ }
+
+ .tableBody tr:hover {
+ background-color: #d0d0d0;
+ }
+
+ .buttons td {
+ width: 200px;
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 20px;
+ }
+
+ a {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ text-decoration: none;
+ color: black;
+ border-radius: 5px;
+ }
+
+ a:hover {
+ background-color: lightgray;
+ }
+ </style>
+</head>
+
+<body onload="loadChart();">
+ <center>
+ <table class="buttons">
+ <tr><td colspan="2"><a href="details-sp2.html" id="windowsbutton">Windows</a></td><td colspan="2"><a href="details-sp2.html?os=osx" id="macbutton">Mac OSX</a></td><td colspan="2"><a href="details-sp2.html?os=linux" id="linuxbutton">Linux</a></td></tr>
+ <tr><td colspan="3" style="height:80px;"><a href="details-sp2.html?os=android" id="mobilebutton">Android</a></td><td colspan="3" style="height:80px;"><a href="details-sp2.html?os=osxm2" id="osxm2button">Mac OSX (M2)</a></td></tr>
+ </table>
+
+ <h3>Current Status (lower is better)</h3>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="myChart" style="width:100%;max-width:900px"></canvas>
+ <table class="buttons">
+ <tr><td><a onclick="changeRange('all')" id="allbutton">All time</a></td><td><a onclick="changeRange(3)" id="month3button">3 months</a></td><td><a onclick="changeRange(1)" id="month1button">1 month</a></td></tr>
+ </table>
+ </div>
+
+ <h3>Breakdown: Speedometer 3 Likely Candidates</h3>
+ <table class="styled-table" id="tableLikely">
+ <col>
+ <col>
+ <colgroup span="2"></colgroup>
+ <col>
+ <colgroup span="2"></colgroup>
+ <col>
+ <thead>
+ <tr><th rowspan="2"></th><th colspan="3" scope="colgroup">Total time (Lower is better)<br />1wk moving average</th><th colspan="2">Difference</th><th colspan="2" scope="colgroup" id="timewindow">6wk prior</th><th rowspan="2">Difference</th><th rowspan="2">Firefox<br />Evolution</th></tr>
+ <tr><th scope="col">Firefox<br />Nightly</th><th scope="col">Chrome<br />Release</th><th scope="col">Chromium-<br />As-Release</th><th scope="col">Chrome<br />Release</th><th scope="col">Chromium-<br />As-Release</th><th scope="col">Firefox<br />Nightly</th><th scope="col">Chrome<br />Release</th></tr>
+ </thead>
+ <tbody class="tableBody" id="tableBodyLikely">
+ </tbody>
+ </table>
+ </center>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ var platform = 'windows10-64-shippable-qr';
+
+ const searchParams = new URLSearchParams(window.location.search);
+
+ let supportsCaR = true;
+
+ let dataSetVisible = [true, true, true];
+ let charts = [];
+
+ if (searchParams.get('os') == 'osx') {
+ platform = 'macosx1015-64-shippable-qr';
+ } else if (searchParams.get('os') == 'osxm2') {
+ platform = 'macosx1400-64-shippable-qr';
+ } else if (searchParams.get('os') == 'linux') {
+ platform = 'linux1804-64-shippable-qr';
+ } else if (searchParams.get('os') == 'android') {
+ platform = 'android-hw-a51-11-0-aarch64-shippable-qr';
+ }
+
+ function getDiffColor(diff) {
+ if (diff < -0.05) {
+ return 'green'
+ } else if (diff < 0.095) {
+ return 'black'
+ } else if (diff < 0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function getSelfDiffColor(diff) {
+ if (diff <= 0.98) {
+ return 'green';
+ } else if (diff >= 1.02) {
+ return 'red';
+ } else {
+ return 'black';
+ }
+ }
+
+ function updateVisibility() {
+ if (dataSetVisible[0]) {
+ document.getElementById("fxbutton").style = "background-color:gray;";
+ } else {
+ document.getElementById("fxbutton").style = "";
+ }
+ if (dataSetVisible[1]) {
+ document.getElementById("chromebutton").style = "background-color:gray;";
+ } else {
+ document.getElementById("chromebutton").style = "";
+ }
+ if (dataSetVisible[2]) {
+ document.getElementById("carbutton").style = "background-color:gray;";
+ } else {
+ document.getElementById("carbutton").style = "";
+ }
+
+ charts.forEach((chart) => {
+ let i = 0;
+ chart.data.datasets.forEach((dataset) => {
+ dataset.hidden = !dataSetVisible[i++];
+ });
+ chart.update();
+ });
+ }
+
+ function loadCharts() {
+ if (searchParams.get('os') == 'osx') {
+ document.getElementById("macbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'osxm2') {
+ document.getElementById("osxm2button").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'linux') {
+ document.getElementById("linuxbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'android') {
+ document.getElementById("mobilebutton").style.backgroundColor = "gray";
+ } else {
+ document.getElementById("windowsbutton").style = "background-color:gray;";
+ }
+ fetch('https://sql.telemetry.mozilla.org/api/queries/93533/results.json?api_key=snFMJTpWr0lnSy2AHg1sAO68BADqDgWC5Cn9Eg6b')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayCharts(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ updateVisibility();
+ }
+
+ function displayCharts(data) {
+ let xyValuesFx = {};
+ let xyValuesChrome = {};
+ let xyValuesCaR = {};
+ let xyValuesSafari = {};
+ let signatures = {};
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != platform) {
+ return;
+ }
+
+ if (typeof xyValuesFx[row.test] == "undefined") {
+ xyValuesFx[row.test] = [];
+ xyValuesChrome[row.test] = [];
+ xyValuesCaR[row.test] = [];
+ xyValuesSafari[row.test] = [];
+ signatures[row.test] = {};
+ }
+
+ signatures[row.test][row.application] = row.signature_id;
+
+ if (row.application == 'firefox' || row.application == 'fenix') { xyValuesFx[row.test].push({ x: row.push_timestamp, y: row.mean }); }
+ if (row.application == 'chrome' || row.application == 'chrome-m') { xyValuesChrome[row.test].push({ x: row.push_timestamp, y: row.mean }); }
+ if (row.application == 'custom-car' || row.application == 'cstm-car-m') { xyValuesCaR[row.test].push({ x: row.push_timestamp, y: row.mean }); }
+ if (row.application == 'safari') { xyValuesSafari[row.test].push({ x: row.push_timestamp, y: row.mean }); }
+ });
+
+ let i = 0;
+ let cfg = {};
+ for (var test in xyValuesFx) {
+ let chartHolder = document.getElementById("chart-holder");
+
+ graphLink = "https://treeherder.mozilla.org/perfherder/graphs?highlightAlerts=1&highlightChangelogData=1&highlightCommonAlerts=0";
+
+ for (var app in signatures[test]) {
+ graphLink += "&series=mozilla-central," + signatures[test][app] + ",1,13"
+ }
+
+ chartHolder.innerHTML += '<center><h3>' + test + ' <a style="padding-left: 10px; padding-right: 10px; " href="' + graphLink + '">🔗</a></h3></center><canvas id="myChart-' + test + '" style="width: 100%; max-width: 900px"></canvas>';
+ }
+
+
+ for (var test in xyValuesFx) {
+ let cfg = {
+ type: "scatter",
+ data: {
+ datasets: [
+ {
+ label: 'Firefox',
+ pointRadius: 4,
+ pointBackgroundColor: "#FF9500",
+ data: xyValuesFx[test]
+ },
+ {
+ label: 'Chrome',
+ pointRadius: 4,
+ pointBackgroundColor: "#1DA462",
+ data: xyValuesChrome[test]
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 1.5,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'day'
+ }
+ },
+ y: {
+ beginAtZero: true
+ }
+ },
+ }
+ };
+
+ if (xyValuesCaR[test].length > 0) {
+ cfg.data.datasets.push({
+ label: 'Chromium-as-Release',
+ pointRadius: 4,
+ pointBackgroundColor: "#0099ff",
+ data: xyValuesCaR[test]
+ });
+ }
+
+ if (xyValuesSafari[test].length > 0) {
+ cfg.data.datasets.push({
+ label: 'Safari',
+ pointRadius: 4,
+ pointBackgroundColor: "#44444444",
+ pointBorderColor: "#000000",
+ data: xyValuesSafari[test]
+ });
+ }
+
+ charts.push(new Chart("myChart-" + test, cfg));
+ }
+ }
+
+ </script>
+ <style>
+ h3 {
+ font-family: sans-serif;
+ }
+
+ .styled-table {
+ border-collapse: collapse;
+ margin: 25px 0;
+ font-size: 0.9em;
+ font-family: sans-serif;
+ min-width: 400px;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .styled-table thead th {
+ background-color: #3366ff;
+ color: #ffffff;
+ text-align: center;
+ }
+
+ .styled-table th {
+ padding: 12px 15px;
+ }
+
+ .styled-table td {
+ text-align: right;
+ }
+
+ .styled-table .testName {
+ text-align: right;
+ }
+
+ .tableBody tr {
+ border-bottom: 1px solid #dddddd;
+ }
+
+ .tableBody .sumRow {
+ border-top: 2px solid black;
+ }
+
+ .tableBody tr:nth-of-type(odd) {
+ background-color: #f3f3f3;
+ }
+
+ .tableBody tr:nth-of-type(even) {
+ background-color: #e3e3e3;
+ }
+
+ .tableBody tr:hover {
+ background-color: #d0d0d0;
+ }
+
+ .buttons td {
+ width: 200px;
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 20px;
+ }
+
+ a {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ text-decoration: none;
+ color: black;
+ border-radius: 5px;
+ }
+
+ a:hover {
+ background-color: lightgray;
+ }
+ </style>
+</head>
+
+<body onload="loadCharts();">
+ <center>
+ <table class="buttons">
+ <tr><td colspan="2"><a href="details-subtests.html" id="windowsbutton">Windows</a></td><td colspan="2"><a href="details-subtests.html?os=osx" id="macbutton">Mac OSX</a></td><td colspan="2"><a href="details-subtests.html?os=linux" id="linuxbutton">Linux</a></td></tr>
+ <tr><td colspan="3" style="height:80px;"><a href="details-subtests.html?os=android" id="mobilebutton">Android</a></td><td colspan="3" style="height:80px;"><a href="details-subtests.html?os=osxm2" id="osxm2button">Mac OSX (M2)</a></td></tr>
+ <tr><td colspan="2"><a id="fxbutton" href="javascript:dataSetVisible[0] = !dataSetVisible[0]; updateVisibility();">Firefox</a></td><td colspan="2"><a id="chromebutton" href="javascript:dataSetVisible[1] = !dataSetVisible[1]; updateVisibility();">Chrome</a></td><td colspan="2"><a id="carbutton" href="javascript:dataSetVisible[2] = !dataSetVisible[2]; updateVisibility();">CaR</a></td></tr>
+ </table>
+
+ <div style="width:100%;max-width:900px" id="chart-holder">
+
+ </div>
+ </center>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ var platform = 'windows10-64-shippable-qr';
+
+ const searchParams = new URLSearchParams(window.location.search);
+
+ let likelyDataURL = 'https://sql.telemetry.mozilla.org/api/queries/89943/results.json?api_key=8pVTrtmbttRWqE5MGuCplgHncRFHON0JUj5zCSGh';
+ let timeWindow = '6wk';
+ let supportsCaR = true;
+
+ let range = '';
+
+ var timeChart;
+
+ var total_sig_firefox = 4591185;
+ var total_sig_chrome = 4592500;
+ var total_sig_car = 4781109;
+ var total_sig_safari = 0;
+ var total_sig_safari_tp = 0;
+ if (searchParams.get('os') == 'osx') {
+ total_sig_firefox = 4588949;
+ total_sig_chrome = 4589463;
+ total_sig_car = 4836588;
+ platform = 'macosx1015-64-shippable-qr';
+ } else if (searchParams.get('os') == 'osxm2') {
+ total_sig_firefox = 5042783;
+ total_sig_chrome = 5044184;
+ total_sig_car = 5043640;
+ total_sig_safari = 5045302;
+ total_sig_safari_tp = 37211;
+ platform = 'macosx1400-64-shippable-qr';
+ } else if (searchParams.get('os') == 'linux') {
+ total_sig_firefox = 4588786;
+ total_sig_chrome = 4589789;
+ total_sig_car = 4725642;
+ platform = 'linux1804-64-shippable-qr';
+ } else if (searchParams.get('os') == 'android') {
+ total_sig_firefox = 4654149;
+ total_sig_chrome = 4698114;
+ total_sig_car = 4942846;
+ platform = 'android-hw-a51-11-0-aarch64-shippable-qr';
+ likelyDataURL = 'https://sql.telemetry.mozilla.org/api/queries/90959/results.json?api_key=uuoiM8Xdob1HcGB5UxdFG3TvZi6D08kfNR5pWC9O';
+ timeWindow = '4wk';
+ } else if (searchParams.get('os') == 'android-s21') {
+ total_sig_firefox = 5052258;
+ total_sig_chrome = 5051172;
+ total_sig_car = 5052905;
+ platform = 'android-hw-s21-13-0-android-aarch64-shippable-qr';
+ likelyDataURL = 'https://sql.telemetry.mozilla.org/api/queries/90959/results.json?api_key=uuoiM8Xdob1HcGB5UxdFG3TvZi6D08kfNR5pWC9O';
+ timeWindow = '4wk';
+ } else if (searchParams.get('os') == 'android-p6') {
+ total_sig_firefox = 5051862;
+ total_sig_chrome = 5050973;
+ total_sig_car = 5053103;
+ platform = 'android-hw-p6-13-0-android-aarch64-shippable-qr';
+ likelyDataURL = 'https://sql.telemetry.mozilla.org/api/queries/90959/results.json?api_key=uuoiM8Xdob1HcGB5UxdFG3TvZi6D08kfNR5pWC9O';
+ timeWindow = '4wk';
+ }
+
+ fetch(likelyDataURL)
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ loadDataLikely(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+
+ function getDiffColor(diff) {
+ if (diff < -0.05) {
+ return 'green'
+ } else if (diff < 0.095) {
+ return 'black'
+ } else if (diff < 0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function getSelfDiffColor(diff) {
+ if (diff <= 0.98) {
+ return 'green';
+ } else if (diff >= 1.02) {
+ return 'red';
+ } else {
+ return 'black';
+ }
+ }
+
+ function fillData(tableId, row) {
+ if (row.platform != platform) {
+ return;
+ }
+ diffColor = getDiffColor(row.difference);
+ oldDiffColor = getDiffColor(row.olddifference);
+
+ let firefoxDiff = 1.0;
+ if (row.firefoxoldmean > 0) {
+ firefoxDiff = row.firefoxdifference;
+ }
+
+
+ let newLine = '';
+ newLine += '<tr onClick="openTestComparison(' + row.signature_id_firefox + ', ' + row.signature_id_chrome + ', ' + row.signature_id_car + ', ' + row.signature_id_safari + ', ' + row.signature_id_safari_tp + ');"><th scope="row" class="testName">' +
+ row.test.split('/')[0] + '</th><td>' +
+ round(row.firefoxmean, 2) + ' ms</td><td>' +
+ round(row.chromemean, 2) + ' ms</td>';
+ if (supportsCaR) {
+ newLine += '<td>' + round(row.carmean, 2) + ' ms</td>';
+ }
+
+ if (platform == 'macosx1400-64-shippable-qr') {
+ newLine += '<td>' +
+ round(row.safarimean, 2) + ' ms</td>';
+ newLine += '<td>' +
+ round(row.safaritpmean, 2) + ' ms</td>';
+ }
+
+ newLine += '<td style =\'color: ' + diffColor + '\'>' +
+ Math.round(-row.difference * 100) + '\%</td>'
+ if (supportsCaR) {
+ newLine += '<td style=\'color: ' + getDiffColor(row.cardifference) + '\'>' + Math.round(-row.cardifference * 100) + '\%</td>'
+ }
+
+ if (platform == 'macosx1400-64-shippable-qr') {
+ newLine += '<td style=\'color: ' + getDiffColor(row.safaridifference) + '\'>' + Math.round(-row.safaridifference * 100) + '\%</td>'
+ newLine += '<td style=\'color: ' + getDiffColor(row.safaritpdifference) + '\'>' + Math.round(-row.safaritpdifference * 100) + '\%</td>'
+ }
+ newLine += '<td>' +
+ round(row.firefoxoldmean, 2) + ' ms</td><td>' +
+ round(row.chromeoldmean, 2) + ' ms</td><td style=\'color: ' + oldDiffColor + '\'>' +
+ Math.round(-row.olddifference * 100) + '\%</td><td style=\'color: ' + getSelfDiffColor(firefoxDiff) + '\'>' +
+ Math.round(-(1 - firefoxDiff) * 100) + '%</td></tr >\n';
+
+ document.getElementById(tableId).innerHTML += newLine;
+ }
+
+ function loadDataLikely(data) {
+ let table = document.getElementById('tableLikely');
+ if (platform != 'macosx1400-64-shippable-qr') {
+ table.rows[0].cells[1].colSpan = 3;
+ table.rows[0].cells[2].colSpan = 2;
+ table.rows[1].deleteCell(3);
+ table.rows[1].deleteCell(3);
+ table.rows[1].deleteCell(5);
+ table.rows[1].deleteCell(5);
+ }
+ data.query_result.data.rows.forEach(fillData.bind(null, 'tableBodyLikely'));
+
+ document.getElementById('timewindow').innerHTML = timeWindow + ' prior';
+
+ let arithmeticMeanOfLogsFX = 0;
+ let arithmeticMeanOfLogsFXOld = 0;
+ let arithmeticMeanOfLogsChrome = 0;
+ let arithmeticMeanOfLogsChromeOld = 0;
+ let arithmeticMeanOfLogsCaR = 0;
+ let arithmeticMeanOfLogsSafari = 0;
+ let arithmeticMeanOfLogsSafariTP = 0;
+ let numValues = 0;
+ let numValuesOld = 0;
+ data.query_result.data.rows.forEach(function (row) {
+ if ((row.platform != platform)) {
+ return;
+ }
+ numValues++;
+ arithmeticMeanOfLogsFX += Math.log(row.firefoxmean);
+ arithmeticMeanOfLogsChrome += Math.log(row.chromemean);
+ arithmeticMeanOfLogsCaR += Math.log(row.carmean);
+ arithmeticMeanOfLogsSafari += Math.log(row.safarimean);
+ arithmeticMeanOfLogsSafariTP += Math.log(row.safaritpmean);
+ if (row.firefoxoldmean > 0) {
+ numValuesOld++;
+ arithmeticMeanOfLogsFXOld += Math.log(row.firefoxoldmean);
+ arithmeticMeanOfLogsChromeOld += Math.log(row.chromeoldmean);
+ }
+ });
+ let FxGeoMean = Math.exp(arithmeticMeanOfLogsFX / numValues);
+ let ChromeGeoMean = Math.exp(arithmeticMeanOfLogsChrome / numValues);
+ let CaRGeoMean = Math.exp(arithmeticMeanOfLogsCaR / numValues);
+ let SafariGeoMean = Math.exp(arithmeticMeanOfLogsSafari / numValues);
+ let SafariTPGeoMean = Math.exp(arithmeticMeanOfLogsSafariTP / numValues);
+ let FxOldGeoMean = Math.exp(arithmeticMeanOfLogsFXOld / numValuesOld);
+ let ChromeOldGeoMean = Math.exp(arithmeticMeanOfLogsChromeOld / numValuesOld);
+
+ let diff = FxGeoMean / ChromeGeoMean - 1;
+ let CaRdiff = FxGeoMean / CaRGeoMean - 1;
+ let Safaridiff = FxGeoMean / SafariGeoMean - 1;
+ let SafariTPdiff = FxGeoMean / SafariTPGeoMean - 1;
+ let oldDiff = ChromeOldGeoMean > 0 ? (FxOldGeoMean / ChromeOldGeoMean - 1) : 0;
+ let diffColor = getDiffColor(diff);
+ let oldDiffColor = getDiffColor(oldDiff);
+ let firefoxDiff = 0;
+ if (FxOldGeoMean > 0) {
+ firefoxDiff = FxGeoMean / FxOldGeoMean;
+ }
+
+ let newLine = '<tr onClick="openTestComparison(' + total_sig_firefox + ', ' + total_sig_chrome + ', ' + total_sig_car + ', ' + total_sig_safari + ', ' + total_sig_safari_tp + ');" class="sumRow"><th scope="row" class="testName">Total Score</th><td>' +
+ round(FxGeoMean, 2) + ' ms</td><td>' +
+ round(ChromeGeoMean, 2) + ' ms</td>';
+
+ if (supportsCaR) {
+ newLine += '<td>' +
+ round(CaRGeoMean, 2) + ' ms</td>';
+ }
+
+ if (platform == 'macosx1400-64-shippable-qr') {
+ newLine += '<td>' +
+ round(SafariGeoMean, 2) + ' ms</td>';
+ newLine += '<td>' +
+ round(SafariTPGeoMean, 2) + ' ms</td>';
+ }
+
+ newLine += '<td style=\'color: ' + diffColor + '\'>' +
+ round(-diff * 100, 2) + '\%</td>';
+ if (supportsCaR) {
+ newLine += '<td style=\'color: ' + getDiffColor(CaRdiff) + '\'>' +
+ round(-CaRdiff * 100, 2) + '\%</td>';
+ }
+
+ if (platform == 'macosx1400-64-shippable-qr') {
+ newLine += '<td style=\'color: ' + getDiffColor(Safaridiff) + '\'>' +
+ round(-Safaridiff * 100, 2) + '\%</td>';
+ newLine += '<td style=\'color: ' + getDiffColor(SafariTPdiff) + '\'>' +
+ round(-SafariTPdiff * 100, 2) + '\%</td>';
+ }
+
+ newLine += '<td>' +
+ round(FxOldGeoMean, 2) + ' ms</td><td>' +
+ round(ChromeOldGeoMean, 2) + ' ms</td><td style=\'color: ' + oldDiffColor + '\'>' +
+ round(-oldDiff * 100, 2) + '\%</td><td style=\'color: ' + getSelfDiffColor(firefoxDiff) + '\'>' +
+ Math.round(-(1 - firefoxDiff) * 100) + '%</td></tr >\n';
+
+ document.getElementById("tableBodyLikely").innerHTML += newLine;
+ }
+
+ function openTestComparison(signatureFirefox, signatureChrome, signatureCaR, signatureSafari, signatureSafariTP) {
+ let repoFirefox = 'mozilla-central';
+ let repoChrome = 'mozilla-central';
+
+ let linkString = "https://treeherder.mozilla.org/perfherder/graphs?highlightAlerts=1&highlightChangelogData=1&highlightCommonAlerts=0&series=" + repoFirefox + "," + signatureFirefox + ",1,13&series=" + repoChrome + "," + signatureChrome + ",1,13&timerange=7776000";
+ if (supportsCaR) {
+ linkString += "&series=" + repoChrome + "," + signatureCaR + ",1,13";
+ }
+ if (signatureSafari > 0) {
+ linkString += "&series=" + repoChrome + "," + signatureSafari + ",1,13";
+ }
+ if (signatureSafariTP > 0) {
+ linkString += "&series=" + repoChrome + "," + signatureSafariTP + ",1,13";
+ }
+ window.open(linkString, "_blank")
+ }
+
+ function loadChart() {
+ if (searchParams.get('os') == 'osx') {
+ document.getElementById("macbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'linux') {
+ document.getElementById("linuxbutton").style = "background-color:gray;";
+ } else if (searchParams.get('os') == 'android') {
+ document.getElementById("mobilebutton").style.backgroundColor = "gray";
+ } else if (searchParams.get('os') == 'android-s21') {
+ document.getElementById("mobilebutton2").style.backgroundColor = "gray";
+ } else if (searchParams.get('os') == 'android-p6') {
+ document.getElementById("mobilebutton3").style.backgroundColor = "gray";
+ } else if (searchParams.get('os') == 'osxm2') {
+ document.getElementById("osxm2button").style.backgroundColor = "gray";
+ } else {
+ document.getElementById("windowsbutton").style = "background-color:gray;";
+ }
+ fetch('https://sql.telemetry.mozilla.org/api/queries/89971/results.json?api_key=6cd9JzffuVjIytWO8fuXs33HXKRjiy9bHJmHfndj')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayChart(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ }
+
+ function displayChart(data) {
+ const ctx = document.getElementById('myChart').getContext('2d');
+ let xyValuesFx = [];
+ let xyValuesChrome = [];
+ let xyValuesCaR = [];
+ let xyValuesSafari = [];
+ let xyValuesSafariTP = [];
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != platform) {
+ if (!(row.platform == 'macosx1300-64-shippable-qr' && platform == 'macosx1400-64-shippable-qr')) {
+ return;
+ }
+ }
+
+ if (row.geomean > 130 && !(platform == 'android-hw-a51-11-0-aarch64-shippable-qr' || platform == 'android-hw-s21-13-0-android-aarch64-shippable-qr' || platform == 'android-hw-p6-13-0-android-aarch64-shippable-qr')) {
+ return;
+ }
+
+ if (row.platform == 'macosx1300-64-shippable-qr' && row.application == 'chrome' && new Date(row.push_timestamp) < new Date('2024-01-24 00:00')) {
+ return;
+ }
+
+ if (row.application == 'firefox' || row.application == 'fenix') { xyValuesFx.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'chrome' || row.application == 'chrome-m') { xyValuesChrome.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'custom-car' || row.application == 'cstm-car-m') { xyValuesCaR.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'safari') { xyValuesSafari.push({ x: row.push_timestamp, y: row.geomean }); }
+ if (row.application == 'safari-tp') { xyValuesSafariTP.push({ x: row.push_timestamp, y: row.geomean }); }
+ });
+
+ let cfg = {
+ type: "scatter",
+ data: {
+ datasets: [
+ {
+ label: 'Firefox',
+ pointRadius: 3,
+ pointBackgroundColor: "#FF9500",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesFx
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 1.5,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ }
+ },
+ y: {
+ beginAtZero: true
+ }
+ },
+ plugins: {
+ annotation: {
+ annotations: {
+ line5: {
+ type: 'line',
+ xMin: '2023-06-07 00:00',
+ xMax: '2023-06-07 00:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label5: {
+ type: 'label',
+ xValue: '2023-06-07 00:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Multiple Tests Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line6: {
+ type: 'line',
+ xMin: '2023-06-15 08:00',
+ xMax: '2023-06-15 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label6: {
+ type: 'label',
+ xValue: '2023-06-15 08:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Perf-Dashboard Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line7: {
+ type: 'line',
+ xMin: '2023-07-04 21:00',
+ xMax: '2023-07-04 21:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label7: {
+ type: 'label',
+ xValue: '2023-07-04 21:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['rAF Switch/Tests Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line8: {
+ type: 'line',
+ xMin: '2023-12-30 17:00',
+ xMax: '2023-12-30 17:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label8: {
+ type: 'label',
+ xValue: '2023-12-30 17:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Complex-DOM Workloads/Freeze'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line9: {
+ type: 'line',
+ xMin: '2024-03-09 00:00',
+ xMax: '2024-03-09 00:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label9: {
+ type: 'label',
+ xValue: '2024-03-09 00:00',
+ yValue: platform == 'android-hw-a51-11-0-aarch64-shippable-qr' ? 200 : 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Release'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ }
+ }
+ }
+ }
+ };
+
+ if (platform == 'android-hw-s21-13-0-android-aarch64-shippable-qr' || platform == 'android-hw-p6-13-0-android-aarch64-shippable-qr') {
+ cfg.options.plugins = {};
+ }
+
+ cfg.data.datasets.push({
+ label: 'Chrome',
+ pointRadius: 3,
+ pointBackgroundColor: "#1DA462",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesChrome
+ });
+
+ if (xyValuesCaR.length > 0) {
+ cfg.data.datasets.push({
+ label: 'Chromium-as-Release',
+ pointRadius: 3,
+ pointBackgroundColor: "#2773da",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesCaR
+ });
+ }
+
+ if (platform == 'macosx1400-64-shippable-qr') {
+ cfg.data.datasets.push({
+ label: 'Safari',
+ pointRadius: 3,
+ pointBackgroundColor: "#44444444",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesSafari
+ });
+ cfg.options.scales.x.min = '2023-12-01';
+ }
+
+ timeChart = new Chart("myChart", cfg);
+ }
+
+ function changeRange(newRange) {
+ if (newRange == 'all') {
+ if (platform != 'macosx1400-64-shippable-qr') {
+ timeChart.options.scales.x.min = '';
+ } else {
+ timeChart.options.scales.x.min = '2023-12-01';
+ }
+ } else {
+ var d = new Date();
+ d.setMonth(d.getMonth() - newRange);
+ timeChart.options.scales.x.min = d;
+ }
+ timeChart.update();
+ }
+
+ </script>
+ <style>
+ h3 {
+ font-family: sans-serif;
+ }
+
+ .styled-table {
+ border-collapse: collapse;
+ margin: 25px 0;
+ font-size: 0.9em;
+ font-family: sans-serif;
+ min-width: 400px;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .styled-table thead th {
+ background-color: #3366ff;
+ color: #ffffff;
+ text-align: center;
+ }
+
+ .styled-table th {
+ padding: 12px 15px;
+ }
+
+ .styled-table td {
+ text-align: right;
+ }
+
+ .styled-table .testName {
+ text-align: left;
+ }
+
+ .tableBody tr {
+ border-bottom: 1px solid #dddddd;
+ }
+
+ .tableBody .sumRow {
+ border-top: 2px solid black;
+ }
+
+ .tableBody tr:nth-of-type(odd) {
+ background-color: #f3f3f3;
+ }
+
+ .tableBody tr:nth-of-type(even) {
+ background-color: #e3e3e3;
+ }
+
+ .tableBody tr:hover {
+ background-color: #d0d0d0;
+ }
+
+ .buttons td {
+ width: 250px;
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 20px;
+ }
+
+ a {
+ padding-left: 30px;
+ padding-right: 30px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ text-decoration: none;
+ color: black;
+ border-radius: 5px;
+ }
+
+ a:hover {
+ background-color: lightgray;
+ }
+ </style>
+</head>
+
+<body onload="loadChart();">
+ <center>
+ <table class="buttons">
+ <tr><td colspan="6" style="height:80px;"><a href="index.html">Overall</a></td></tr>
+ <tr><td colspan="3"><a href="details.html" id="windowsbutton">Windows</a></td><td colspan="3"><a href="details.html?os=linux" id="linuxbutton">Linux</a></td></tr>
+ <tr><td colspan="3"><a href="details.html?os=osx" id="macbutton">Mac OSX</a></td><td colspan="3" style="height:50px;"><a href="details.html?os=osxm2" id="osxm2button">Mac OSX (M2)</a></td></tr>
+ <tr><td colspan="2" style="height:50px;"><a href="details.html?os=android" id="mobilebutton">Android (A51)</a></td><td colspan="2" style="height:50px;"><a href="details.html?os=android-s21" id="mobilebutton2">Android (S21)</a></td><td colspan="2" style="height:50px;"><a href="details.html?os=android-p6" id="mobilebutton3">Android (Pixel 6)</a></td></tr>
+ </table>
+
+ <h3>Current Status (lower is better)</h3>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="myChart" style="width:100%;max-width:900px"></canvas>
+ <table class="buttons">
+ <tr><td><a onclick="changeRange('all')" id="allbutton">All time</a></td><td><a onclick="changeRange(3)" id="month3button">3 months</a></td><td><a onclick="changeRange(1)" id="month1button">1 month</a></td></tr>
+ </table>
+ </div>
+
+ <h3>Breakdown: Speedometer 3 Likely Candidates</h3>
+ <table class="styled-table" id="tableLikely">
+ <col>
+ <col>
+ <colgroup span="2"></colgroup>
+ <col>
+ <colgroup span="2"></colgroup>
+ <col>
+ <thead>
+ <tr><th rowspan="2"></th><th colspan="5" scope="colgroup">Total time (Lower is better)<br />1wk moving average</th><th colspan="4">Difference</th><th colspan="2" scope="colgroup" id="timewindow">6wk prior</th><th rowspan="2">Difference</th><th rowspan="2">Firefox<br />Evolution</th></tr>
+ <tr><th scope="col">Firefox<br />Nightly</th><th scope="col">Chrome<br />Release</th><th scope="col">Chromium-<br />As-Release</th><th scope="col">Safari<br/>Release</th><th scope="col">Safari<br />TP</th><th scope="col">Chrome<br />Release</th><th scope="col">Chromium-<br />As-Release</th><th scope="col">Safari<br/>Release</th><th scope="col">Safari<br />TP</th><th scope="col">Firefox<br />Nightly</th><th scope="col">Chrome<br />Release</th></tr>
+ </thead>
+ <tbody class="tableBody" id="tableBodyLikely">
+ </tbody>
+ </table>
+ </center>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ function getDiffColor(diff) {
+ if (diff < -0.05) {
+ return 'green'
+ } else if (diff < 0.095) {
+ return 'black'
+ } else if (diff < 0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function loadChart() {
+ fetch('https://sql.telemetry.mozilla.org/api/queries/91105/results.json?api_key=l1VW7NobZMxWLDNpLHMYMMcLsBKFSeeoWBZi0gpZ')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayChart(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ }
+
+ function getPlatformWeight(platform) {
+ switch (platform) {
+ case 'windows10-64-shippable-qr':
+ return 0.8;
+ case 'macosx1015-64-shippable-qr':
+ return 0.2;
+ default:
+ return 0.0;
+ }
+ }
+
+ function displayChart(data) {
+ const ctxDesktop = document.getElementById('chartDesktop').getContext('2d');
+
+ let xyValues = {};
+
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.difference == null) {
+ return;
+ }
+
+ if (!xyValues.hasOwnProperty(row.platform)) {
+ xyValues[row.platform] = [];
+ }
+
+ xyValues[row.platform].push({ x: row.push_timestamp, y: -row.moving_difference * 100 });
+ });
+
+
+ new Chart("chartDesktop", {
+ type: "line",
+ data: {
+ datasets: [
+ {
+ label: 'Windows',
+ data: xyValues['windows10-64-shippable-qr']
+ },
+ {
+ label: 'Mac OS',
+ data: xyValues['macosx1015-64-shippable-qr']
+ },
+ {
+ label: 'Linux',
+ data: xyValues['linux1804-64-shippable-qr']
+ },
+ {
+ label: 'Android',
+ data: xyValues['android-hw-a51-11-0-aarch64-shippable-qr']
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 2,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ }
+ },
+ y: {
+ beginAtZero: true,
+ title: {
+ display: true,
+ text: 'Performance Difference (%)'
+ },
+ }
+ }
+ }
+ });
+ }
+
+ </script>
+ <style>
+ h2 {
+ font-family: sans-serif;
+ }
+
+ th {
+ font-family: sans-serif;
+ font-size: 22px;
+ text-align: center;
+ width: 180px;
+ }
+
+ td {
+ font-family: sans-serif;
+ font-size: 20px;
+ text-align: center;
+ }
+
+ .buttons td {
+ width: 200px;
+ }
+
+ a {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ text-decoration: none;
+ color: black;
+ border-radius: 5px;
+ }
+
+ a:hover {
+ background-color: lightgray;
+ }
+ </style>
+</head>
+
+<body onload="loadChart();">
+ <center>
+
+ <h2>Speedometer 3 Comparison to Chrome</h2>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="chartDesktop" style="width:100%;max-width:900px"></canvas>
+ </div>
+
+ </center>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ function getDiffColor(diff) {
+ if (diff < -0.05) {
+ return 'green'
+ } else if (diff < 0.095) {
+ return 'black'
+ } else if (diff < 0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function loadChart() {
+ fetch('https://sql.telemetry.mozilla.org/api/queries/91105/results.json?api_key=l1VW7NobZMxWLDNpLHMYMMcLsBKFSeeoWBZi0gpZ')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayChart(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ }
+
+ function getPlatformWeight(platform) {
+ switch (platform) {
+ case 'windows10-64-shippable-qr':
+ return 0.8;
+ case 'macosx1015-64-shippable-qr':
+ return 0.2;
+ default:
+ return 0.0;
+ }
+ }
+
+ function displayChart(data) {
+ const ctxDesktop = document.getElementById('chartDesktop').getContext('2d');
+
+ var weightedValuesDesktop = {};
+ var weightedValuesMobile = {};
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform == 'android-hw-a51-11-0-aarch64-shippable-qr' || row.difference == null) {
+ return;
+ }
+
+ if (!weightedValuesDesktop.hasOwnProperty(row.push_timestamp)) {
+ weightedValuesDesktop[row.push_timestamp] = {};
+ weightedValuesDesktop[row.push_timestamp]['diff'] = 0;
+ weightedValuesDesktop[row.push_timestamp]['totalWeight'] = 0;
+ }
+
+ weightedValuesDesktop[row.push_timestamp]['diff'] += getPlatformWeight(row.platform) * -row.moving_difference;
+ weightedValuesDesktop[row.push_timestamp]['totalWeight'] += getPlatformWeight(row.platform);
+ });
+
+ data.query_result.data.rows.forEach(function (row) {
+ if (row.platform != 'android-hw-a51-11-0-aarch64-shippable-qr' || row.difference == null) {
+ return;
+ }
+
+ if (!weightedValuesMobile.hasOwnProperty(row.push_timestamp)) {
+ weightedValuesMobile[row.push_timestamp] = {};
+ weightedValuesMobile[row.push_timestamp]['diff'] = 0;
+ weightedValuesMobile[row.push_timestamp]['totalWeight'] = 0;
+ }
+
+ weightedValuesMobile[row.push_timestamp]['diff'] += -row.moving_difference;
+ weightedValuesMobile[row.push_timestamp]['totalWeight'] += 1.0;
+ });
+
+ let xyValues = [];
+ let xyValuesMobile = [];
+ let xyValuesTrend = [];
+
+ for (const timestamp in weightedValuesDesktop) {
+ if (weightedValuesDesktop[timestamp]['totalWeight'] > 0.999) {
+ xyValues.push({ x: timestamp, y: (weightedValuesDesktop[timestamp]['diff']) * 100 });
+ }
+ }
+
+
+ for (const timestamp in weightedValuesMobile) {
+ if (weightedValuesMobile[timestamp]['totalWeight'] > 0.999) {
+ xyValuesMobile.push({ x: timestamp, y: (weightedValuesMobile[timestamp]['diff']) * 100 });
+ }
+ }
+
+ new Chart("chartDesktop", {
+ type: "line",
+ data: {
+ datasets: [
+ {
+ label: 'Difference',
+ data: xyValues
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 2,
+ plugins: { legend: { display: false } },
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ },
+ min: '2023-04-14'
+
+ },
+ y: {
+ beginAtZero: true,
+ title: {
+ display: true,
+ text: 'Performance Difference (%)'
+ },
+ }
+ }
+ }
+ });
+
+ new Chart("chartMobile", {
+ type: "line",
+ data: {
+ datasets: [
+ {
+ label: 'Difference',
+ data: xyValuesMobile
+ },
+ ]
+ },
+ options: {
+ aspectRatio: 2,
+ plugins: { legend: { display: false } },
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ },
+ min: '2023-04-14'
+ },
+ y: {
+ beginAtZero: true,
+ title: {
+ display: true,
+ text: 'Performance Difference (%)'
+ },
+ }
+ }
+ }
+ });
+ }
+
+ </script>
+ <style>
+ h2 {
+ font-family: sans-serif;
+ }
+
+ th {
+ font-family: sans-serif;
+ font-size: 22px;
+ text-align: center;
+ width: 180px;
+ }
+
+ td {
+ font-family: sans-serif;
+ font-size: 20px;
+ text-align: center;
+ }
+
+ .buttons td {
+ width: 200px;
+ }
+
+ a {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ text-decoration: none;
+ color: black;
+ border-radius: 5px;
+ }
+
+ a:hover {
+ background-color: lightgray;
+ }
+ </style>
+</head>
+
+<body onload="loadChart();">
+ <center>
+
+ <h2>Desktop</h2>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="chartDesktop" style="width:100%;max-width:900px"></canvas>
+ </div>
+
+ <h2>Mobile</h2>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="chartMobile" style="width:100%;max-width:900px"></canvas>
+ </div>
+
+ </center>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title>Speedometer 3 Status Dashboard</title>
+
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
+
+ <script>
+ var chartMobile;
+ var chartDesktop;
+
+ function round(number, decimals) {
+ return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals);
+ }
+
+ function getDiffColor(diff) {
+ if (diff < -0.05) {
+ return 'green'
+ } else if (diff < 0.095) {
+ return 'black'
+ } else if (diff < 0.2) {
+ return '#b38f00'
+ } else {
+ return 'red'
+ }
+ }
+
+ function loadDataLikely(data) {
+ let arithmeticMeanOfLogsFX = {};
+ let arithmeticMeanOfLogsChrome = {};
+ let arithmeticMeanOfLogsCaR = {};
+ let numValues = {};
+ data.query_result.data.rows.forEach(function (row) {
+ if (!arithmeticMeanOfLogsFX.hasOwnProperty(row.platform)) {
+ arithmeticMeanOfLogsFX[row.platform] = 0;
+ arithmeticMeanOfLogsChrome[row.platform] = 0;
+ arithmeticMeanOfLogsCaR[row.platform] = 0;
+ numValues[row.platform] = 0;
+ }
+ numValues[row.platform]++;
+ arithmeticMeanOfLogsFX[row.platform] += Math.log(row.firefoxmean);
+ arithmeticMeanOfLogsChrome[row.platform] += Math.log(row.chromemean);
+ arithmeticMeanOfLogsCaR[row.platform] += Math.log(row.carmean);
+ });
+
+ let FxGeoMeanDesktop = 0;
+ let ChromeGeoMeanDesktop = 0
+ let CaRGeoMeanDesktop = 0
+ for (const platform in arithmeticMeanOfLogsFX) {
+ FxGeoMeanDesktop += Math.exp(arithmeticMeanOfLogsFX[platform] / numValues[platform]) * getPlatformWeight(platform);
+ ChromeGeoMeanDesktop += Math.exp(arithmeticMeanOfLogsChrome[platform] / numValues[platform]) * getPlatformWeight(platform);
+ CaRGeoMeanDesktop += Math.exp(arithmeticMeanOfLogsCaR[platform] / numValues[platform]) * getPlatformWeight(platform);
+ }
+
+ let FxGeoMeanMobile = Math.exp(arithmeticMeanOfLogsFX['android-hw-a51-11-0-aarch64-shippable-qr'] /
+ numValues['android-hw-a51-11-0-aarch64-shippable-qr'])
+ let ChromeGeoMeanMobile = Math.exp(arithmeticMeanOfLogsChrome['android-hw-a51-11-0-aarch64-shippable-qr'] /
+ numValues['android-hw-a51-11-0-aarch64-shippable-qr'])
+ let CaRGeoMeanMobile = Math.exp(arithmeticMeanOfLogsCaR['android-hw-a51-11-0-aarch64-shippable-qr'] /
+ numValues['android-hw-a51-11-0-aarch64-shippable-qr'])
+ let diffDesktop = FxGeoMeanDesktop / ChromeGeoMeanDesktop - 1;
+ let diffMobile = (FxGeoMeanMobile / ChromeGeoMeanMobile) - 1;
+ let diffDesktopCaR = FxGeoMeanDesktop / CaRGeoMeanDesktop - 1;
+ let diffMobileCaR = (FxGeoMeanMobile / CaRGeoMeanMobile) - 1;
+
+ document.getElementById("firefoxTimeDesktop").innerHTML += round(FxGeoMeanDesktop, 2) + ' ms';
+ document.getElementById("chromeTimeDesktop").innerHTML += round(ChromeGeoMeanDesktop, 2) + ' ms';
+ document.getElementById("carTimeDesktop").innerHTML += round(CaRGeoMeanDesktop, 2) + ' ms';
+ document.getElementById("firefoxTimeMobile").innerHTML += round(FxGeoMeanMobile, 2) + ' ms';
+ document.getElementById("chromeTimeMobile").innerHTML += round(ChromeGeoMeanMobile, 2) + ' ms';
+ document.getElementById("carTimeMobile").innerHTML += round(CaRGeoMeanMobile, 2) + ' ms';
+
+ document.getElementById("KRscoreDesktop").innerHTML += '<p style="margin:0px;padding:0;color:' + getDiffColor(diffDesktop) + ';">' + -round(diffDesktop * 100, 1) + '%</p>';
+ document.getElementById("KRscoreMobile").innerHTML += '<p style="margin:0px;padding:0;color:' + getDiffColor(diffMobile) + ';">' + -round(diffMobile * 100, 1) + '%</p>';
+ document.getElementById("futScoreDesktop").innerHTML += '<p style="margin:0px;padding:0;color:' + getDiffColor(diffDesktopCaR) + ';">' + -round(diffDesktopCaR * 100, 1) + '%</p>';
+ document.getElementById("futScoreMobile").innerHTML += '<p style="margin:0px;padding:0;color:' + getDiffColor(diffMobileCaR) + ';">' + -round(diffMobileCaR * 100, 1) + '%</p>';
+ }
+
+ fetch('https://sql.telemetry.mozilla.org/api/queries/89943/results.json?api_key=8pVTrtmbttRWqE5MGuCplgHncRFHON0JUj5zCSGh')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ loadDataLikely(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+
+ function loadChart() {
+ fetch('https://sql.telemetry.mozilla.org/api/queries/96199/results.json?api_key=DtrYOBSoDrUaeuxRfvXPdlDiOS5sqrbsGcXyM5Q2')
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (data) {
+ displayChart(data);
+ })
+ .catch(function (err) {
+ console.log('error: ' + err);
+ });
+ }
+
+ function getPlatformWeight(platform) {
+ switch (platform) {
+ case 'windows10-64-shippable-qr':
+ return 0.8;
+ case 'macosx1015-64-shippable-qr':
+ return 0.2;
+ default:
+ return 0.0;
+ }
+ }
+
+ function displayChart(data) {
+ const ctxDesktop = document.getElementById('chartDesktop').getContext('2d');
+ const ctxMobile = document.getElementById('chartMobile').getContext('2d');
+
+ var weightedValuesDesktop = {};
+ var weightedValuesMobile = {};
+ data.query_result.data.rows.forEach(function (row) {
+ if (!weightedValuesDesktop.hasOwnProperty(row.push_timestamp)) {
+ weightedValuesDesktop[row.push_timestamp] = {};
+ }
+ if (!weightedValuesDesktop[row.push_timestamp].hasOwnProperty(row.application)) {
+ weightedValuesDesktop[row.push_timestamp][row.application] = {};
+ weightedValuesDesktop[row.push_timestamp][row.application]['value'] = 0;
+ weightedValuesDesktop[row.push_timestamp][row.application]['totalWeight'] = 0;
+ }
+
+ weightedValuesDesktop[row.push_timestamp][row.application]['value'] += getPlatformWeight(row.platform) * row.geomean;
+ weightedValuesDesktop[row.push_timestamp][row.application]['totalWeight'] += getPlatformWeight(row.platform);
+ if (row.platform == 'android-hw-a51-11-0-aarch64-shippable-qr') {
+ if (!weightedValuesMobile.hasOwnProperty(row.push_timestamp)) {
+ weightedValuesMobile[row.push_timestamp] = {};
+ }
+ weightedValuesMobile[row.push_timestamp][row.application] = row.geomean;
+ }
+ });
+
+ let xyValuesFx = [];
+ let xyValuesChrome = [];
+ let xyValuesCaR = [];
+ let xyValuesFenix = [];
+ let xyValuesChromeM = [];
+ let xyValuesCaRM = [];
+ for (const timestamp in weightedValuesDesktop) {
+ // May need hack to remove values where a run failed.
+
+ if (weightedValuesDesktop[timestamp].hasOwnProperty('firefox')) {
+ if (weightedValuesDesktop[timestamp]['firefox']['value'] < 200 && weightedValuesDesktop[timestamp]['firefox']['totalWeight'] > 0.999) {
+ xyValuesFx.push({ x: timestamp, y: weightedValuesDesktop[timestamp]['firefox']['value'] });
+ }
+ }
+ if (weightedValuesDesktop[timestamp].hasOwnProperty('chrome')) {
+ if (weightedValuesDesktop[timestamp]['chrome']['value'] < 145 && weightedValuesDesktop[timestamp]['chrome']['totalWeight'] > 0.999) {
+ xyValuesChrome.push({ x: timestamp, y: weightedValuesDesktop[timestamp]['chrome']['value'] });
+ }
+ }
+ if (weightedValuesDesktop[timestamp].hasOwnProperty('custom-car')) {
+ if (weightedValuesDesktop[timestamp]['custom-car']['value'] < 145 && weightedValuesDesktop[timestamp]['custom-car']['totalWeight'] > 0.999) {
+ xyValuesCaR.push({ x: timestamp, y: weightedValuesDesktop[timestamp]['custom-car']['value'] });
+ }
+ }
+ }
+
+ for (const timestamp in weightedValuesMobile) {
+ if (weightedValuesMobile[timestamp].hasOwnProperty('fenix')) {
+ if (weightedValuesMobile[timestamp]['fenix'] < 950) {
+ xyValuesFenix.push({ x: timestamp, y: weightedValuesMobile[timestamp]['fenix'] });
+ }
+ }
+ if (weightedValuesMobile[timestamp].hasOwnProperty('chrome-m')) {
+ xyValuesChromeM.push({ x: timestamp, y: weightedValuesMobile[timestamp]['chrome-m'] });
+ }
+ if (weightedValuesMobile[timestamp].hasOwnProperty('cstm-car-m')) {
+ xyValuesCaRM.push({ x: timestamp, y: weightedValuesMobile[timestamp]['cstm-car-m'] });
+ }
+ }
+
+ chartDesktop = new Chart("chartDesktop", {
+ type: "scatter",
+ data: {
+ datasets: [
+ {
+ label: 'Firefox',
+ pointRadius: 3,
+ pointBackgroundColor: "#FF9500",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesFx
+ },
+ {
+ label: 'Chrome',
+ pointRadius: 3,
+ pointBackgroundColor: "#1DA462",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesChrome
+ },
+ {
+ label: 'Chromium-as-Release',
+ pointRadius: 3,
+ pointBackgroundColor: "#0099ff",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesCaR
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 1.5,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ }
+ },
+ y: {
+ beginAtZero: true
+ }
+ },
+ plugins: {
+ annotation: {
+ annotations: {
+ line4: {
+ type: 'line',
+ xMin: '2023-04-14 08:00',
+ xMax: '2023-04-14 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label4: {
+ type: 'label',
+ xValue: '2023-04-14 08:00',
+ yValue: 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Svelte Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line5: {
+ type: 'line',
+ xMin: '2023-06-07 00:00',
+ xMax: '2023-06-07 00:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label5: {
+ type: 'label',
+ xValue: '2023-06-07 00:00',
+ yValue: 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Multiple Tests Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line6: {
+ type: 'line',
+ xMin: '2023-06-15 08:00',
+ xMax: '2023-06-15 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label6: {
+ type: 'label',
+ xValue: '2023-06-15 08:00',
+ yValue: 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Perf-Dashboard Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line7: {
+ type: 'line',
+ xMin: '2023-07-04 21:00',
+ xMax: '2023-07-04 21:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label7: {
+ type: 'label',
+ xValue: '2023-07-04 21:00',
+ yValue: 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['rAF Switch/Tests Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line8: {
+ type: 'line',
+ xMin: '2023-12-30 17:00',
+ xMax: '2023-12-30 17:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label8: {
+ type: 'label',
+ xValue: '2023-12-30 17:00',
+ yValue: 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Complex-DOM Workloads/Freeze'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line9: {
+ type: 'line',
+ xMin: '2024-03-09 00:00',
+ xMax: '2024-03-09 00:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label9: {
+ type: 'label',
+ xValue: '2024-03-09 00:00',
+ yValue: 40,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Release'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ }
+ }
+ }
+ }
+ });
+ chartMobile = new Chart("chartMobile", {
+ type: "scatter",
+ data: {
+ datasets: [
+ {
+ label: 'Fenix',
+ pointRadius: 3,
+ pointBackgroundColor: "#FF9500",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesFenix
+ },
+ {
+ label: 'Chrome',
+ pointRadius: 3,
+ pointBackgroundColor: "#1DA462",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesChromeM
+ },
+ {
+ label: 'Chromium-as-Release',
+ pointRadius: 3,
+ pointBackgroundColor: "#0099ff",
+ pointBorderColor: "#000000",
+ pointBorderWidth: 0.5,
+ data: xyValuesCaRM
+ }
+ ]
+ },
+ options: {
+ aspectRatio: 1.5,
+ scales: {
+ x: {
+ type: 'time',
+ time: {
+ unit: 'week'
+ }
+ },
+ y: {
+ beginAtZero: true
+ }
+ },
+ plugins: {
+ annotation: {
+ annotations: {
+ line4: {
+ type: 'line',
+ xMin: '2023-04-14 08:00',
+ xMax: '2023-04-14 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label4: {
+ type: 'label',
+ xValue: '2023-04-14 08:00',
+ yValue: 200,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Svelte Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line5: {
+ type: 'line',
+ xMin: '2023-06-07 00:00',
+ xMax: '2023-06-07 00:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label5: {
+ type: 'label',
+ xValue: '2023-06-07 00:00',
+ yValue: 200,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Multiple Tests Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line6: {
+ type: 'line',
+ xMin: '2023-06-15 08:00',
+ xMax: '2023-06-15 08:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label6: {
+ type: 'label',
+ xValue: '2023-06-15 08:00',
+ yValue: 200,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Perf-Dashboard Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line7: {
+ type: 'line',
+ xMin: '2023-07-04 21:00',
+ xMax: '2023-07-04 21:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label7: {
+ type: 'label',
+ xValue: '2023-07-04 21:00',
+ yValue: 200,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['rAF Switch/Tests Added'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line8: {
+ type: 'line',
+ xMin: '2023-12-30 17:00',
+ xMax: '2023-12-30 17:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label8: {
+ type: 'label',
+ xValue: '2023-12-30 17:00',
+ yValue: 200,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Complex-DOM Workloads/Freeze'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ line9: {
+ type: 'line',
+ xMin: '2024-03-09 00:00',
+ xMax: '2024-03-09 00:00',
+ borderColor: 'black',
+ borderWidth: 2,
+ },
+ label9: {
+ type: 'label',
+ xValue: '2024-03-09 00:00',
+ yValue: 200,
+ backgroundColor: 'rgb(255,128,128)',
+ content: ['Release'],
+ font: {
+ size: 14
+ },
+ rotation: -90,
+ borderRadius: 4
+ },
+ }
+ }
+ }
+ }
+ });
+ }
+
+
+ function changeRange(newRange) {
+ if (newRange == 'all') {
+ chartMobile.options.scales.x.min = '';
+ chartDesktop.options.scales.x.min = '';
+ } else {
+ var d = new Date();
+ d.setMonth(d.getMonth() - newRange);
+ chartMobile.options.scales.x.min = d;
+ chartDesktop.options.scales.x.min = d;
+ }
+ chartMobile.update();
+ chartDesktop.update();
+ }
+ </script>
+ <style>
+ h2 {
+ font-family: sans-serif;
+ }
+
+ th {
+ font-family: sans-serif;
+ font-size: 22px;
+ text-align: center;
+ width:180px;
+ }
+
+ td {
+ font-family: sans-serif;
+ font-size: 20px;
+ text-align: center;
+ }
+
+ .buttons td {
+ width:250px;
+ }
+
+ a {
+ padding-left:30px;
+ padding-right:30px;
+ padding-top:10px;
+ padding-bottom:10px;
+ text-decoration:none;
+ color:black;
+ border-radius:5px;
+ }
+ a:hover {
+ background-color:lightgray;
+ }
+ </style>
+</head>
+
+<body onload="loadChart();">
+ <center>
+ <table class="buttons">
+ <tr><td colspan="6" style="height:80px;"><a href="index.html" style="background-color:gray;">Overall</a></td></tr>
+ <tr><td colspan="3"><a href="details.html" id="windowsbutton">Windows</a></td><td colspan="3"><a href="details.html?os=linux" id="linuxbutton">Linux</a></td></tr>
+ <tr><td colspan="3"><a href="details.html?os=osx" id="macbutton">Mac OSX</a></td><td colspan="3" style="height:50px;"><a href="details.html?os=osxm2" id="osxm2button">Mac OSX (M2)</a></td></tr>
+ <tr><td colspan="2" style="height:50px;"><a href="details.html?os=android" id="mobilebutton">Android (A51)</a></td><td colspan="2" style="height:50px;"><a href="details.html?os=android-s21" id="mobilebutton">Android (S21)</a></td><td colspan="2" style="height:50px;"><a href="details.html?os=android" id="mobilebutton">Android (Pixel 6)</a></td></tr>
+ </table>
+
+ <table>
+ <tr><th colspan="2">KR Score</th></tr>
+ <tr><th>Desktop</th><th>Mobile</th></tr>
+ <tr><td id="KRscoreDesktop"></td><td id="KRscoreMobile"></td></tr>
+ </table>
+ <br />
+ <table>
+ <tr><th colspan="2">Future Score (vs CaR)</th></tr>
+ <tr><th>Desktop</th><th>Mobile</th></tr>
+ <tr><td id="futScoreDesktop"></td><td id="futScoreMobile"></td></tr>
+ </table>
+ <br />
+ <table class="buttons">
+ <tr><td><a onclick="changeRange('all')" id="allbutton">All time</a></td><td><a onclick="changeRange(3)" id="month3button">3 months</a></td><td><a onclick="changeRange(1)" id="month1button">1 month</a></td></tr>
+ </table>
+
+ <h2>Desktop Status (lower is better)</h2>
+
+ <table>
+ <tr><th>Firefox</th><th>Chrome</th><th>Chromium-as-Release</th></tr>
+ <tr><td id="firefoxTimeDesktop"></td><td id="chromeTimeDesktop"></td><td id="carTimeDesktop"></td></tr>
+ </table>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="chartDesktop" style="width:100%;max-width:900px"></canvas>
+ </div>
+
+ <br />
+ <h2>Mobile Status (lower is better)</h2>
+
+ <table>
+ <tr><th>Firefox</th><th>Chrome</th><th>Chromium-as-Release</th></tr>
+ <tr><td id="firefoxTimeMobile"></td><td id="chromeTimeMobile"></td><td id="carTimeMobile"></td></tr>
+ </table>
+
+ <div style="width:100%;max-width:900px">
+ <canvas id="chartMobile" style="width:100%;max-width:900px"></canvas>
+ </div>
+ </center>
+</body>
+</html>