jetstream.html (759 lines of code) (raw):

<!DOCTYPE html> <html lang="en"> <head> <title>Jetstream 3 Status Dashboard</title> <link href="https://fonts.googleapis.com/css2?family=Zilla+Slab:wght@400;700&display=swap" rel="stylesheet"> <link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.1/css/all.min.css" rel="stylesheet"> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <link rel="stylesheet" href="assets/main-ui-style.css"> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/moment/min/moment.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-trendline"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.4/pako.min.js"></script> <script> document.addEventListener("DOMContentLoaded", () => { generateContent(); }); function round(number, decimals) { return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals); } // Set default platform here. var platform = 'windows11-64-24h2-shippable'; const searchParams = new URLSearchParams(window.location.search); let timeWindow = '6wk'; let supportsCaR = true; let range = ''; var timeChart; // Initialize platforms array with current platform var platforms = []; if (searchParams.get('os') == 'windows') { platform = 'windows11-64-24h2-shippable'; } else if (searchParams.get('os') == 'osx') { platform = 'macosx1500-aarch64-shippable'; } else if (searchParams.get('os') == 'linux') { platform = 'linux1804-64-shippable-qr'; } else if (searchParams.get('os') == 'android-a55') { platform = 'android-hw-a55-14-0-aarch64-shippable'; } else if (searchParams.get('os') == 'android-s24') { platform = 'android-hw-s24-14-0-aarch64-shippable'; } else if (searchParams.get('os') == 'android-p6') { platform = 'android-hw-p6-13-0-aarch64-shippable'; } platforms = [platform]; function getDiffColor(diff) { if (diff < -5) { return 'red' } else if (diff > 5) { return 'green' } else { return 'black' } } function getSelfDiffColor(diff) { if (diff <= 0.98) { return 'green'; } else if (diff >= 1.02) { return 'red'; } else { return 'black'; } } // Global variable to store table data for sorting let globalTableData = []; // Current sort state let currentSortColumn = 'testName'; let currentSortDirection = 'asc'; // Function to sort table by column function sortTable(column) { // Toggle sort direction if clicking the same column if (column === currentSortColumn) { currentSortDirection = currentSortDirection === 'asc' ? 'desc' : 'asc'; } else { currentSortColumn = column; currentSortDirection = 'asc'; } // Separate score row from other data const scoreRow = globalTableData.find(row => row.testName === 'score'); const otherRows = globalTableData.filter(row => row.testName !== 'score'); // Sort the data (excluding score) otherRows.sort((a, b) => { let valueA = a[column]; let valueB = b[column]; // Handle string comparison for test name if (column === 'testName') { return currentSortDirection === 'asc' ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA); } // Handle numeric comparison for other columns return currentSortDirection === 'asc' ? valueA - valueB : valueB - valueA; }); // Combine score row with sorted data globalTableData = scoreRow ? [scoreRow, ...otherRows] : otherRows; // Update the table const tableBody = document.getElementById('tableBodyLikely'); tableBody.innerHTML = ''; // Add rows to table globalTableData.forEach(row => { tableBody.innerHTML += row.html; }); // Add total score row back if (document.getElementById('totalScoreRow')) { tableBody.innerHTML += document.getElementById('totalScoreRow').outerHTML; } // Update header styling to show sort direction updateHeaderStyling(); } // Function to update header styling to show sort direction function updateHeaderStyling() { // Reset all headers const headers = document.querySelectorAll('#subtestTable th'); headers.forEach(header => { header.classList.remove('sorted-asc', 'sorted-desc'); }); // Add class to sorted header const columnIndex = getColumnIndex(currentSortColumn); if (columnIndex >= 0) { const header = document.querySelector(`#subtestTable tr:nth-child(2) th:nth-child(${columnIndex + 1})`); if (header) { header.classList.add(currentSortDirection === 'asc' ? 'sorted-asc' : 'sorted-desc'); } } } // Function to get column index from column name function getColumnIndex(column) { switch(column) { case 'testName': return 0; case 'firefoxAvg': return 1; case 'chromeAvg': return 2; case 'carAvg': return 3; case 'safariAvg': return platform.includes('macosx') ? 4 : -1; case 'safariTpAvg': return platform.includes('macosx') ? 5 : -1; case 'chromeDiff': return platform.includes('macosx') ? 6 : 4; case 'carDiff': return platform.includes('macosx') ? 7 : 5; case 'safariDiff': return platform.includes('macosx') ? 8 : -1; case 'safariTpDiff': return platform.includes('macosx') ? 9 : -1; default: return -1; } } function displayTable(data) { let table = document.getElementById('subtestTable'); if (!platform.includes('macosx')) { 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); } // Group data by test name const testGroups = {}; const now = new Date(); const oneWeekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); data.query_result.data.rows.forEach(row => { if (row.platform === platform) { const testName = row.test.split('/')[0]; if (!testGroups[testName]) { testGroups[testName] = { firefox: [], chrome: [], car: [], safari: [], safaritp: [] }; } const rowDate = new Date(row.date); if (rowDate >= oneWeekAgo) { if (row.application === 'firefox' || row.application === 'fenix') { testGroups[testName].firefox.push(row.value); } else if (row.application === 'chrome' || row.application === 'chrome-m') { testGroups[testName].chrome.push(row.value); } else if (row.application === 'custom-car' || row.application === 'cstm-car-m') { testGroups[testName].car.push(row.value); } else if (row.application === 'safari') { testGroups[testName].safari.push(row.value); } else if (row.application === 'safari-tp') { testGroups[testName].safaritp.push(row.value); } } } }); // Calculate averages and prepare table data const tableBody = document.getElementById('tableBodyLikely'); tableBody.innerHTML = ''; // Create array of test data for sorting let tableData = []; // First pass to get signature IDs const signatureIds = {}; data.query_result.data.rows.forEach(row => { if (row.platform === platform) { const testName = row.test.split('/')[0]; if (!signatureIds[testName]) { signatureIds[testName] = { firefox: 0, chrome: 0, car: 0, safari: 0, safaritp: 0 }; } if (row.application === 'firefox' || row.application === 'fenix') { signatureIds[testName].firefox = row.signature_id; } else if (row.application === 'chrome' || row.application === 'chrome-m') { signatureIds[testName].chrome = row.signature_id; } else if (row.application === 'custom-car' || row.application === 'cstm-car-m') { signatureIds[testName].car = row.signature_id; } else if (row.application === 'safari') { signatureIds[testName].safari = row.signature_id; } else if (row.application === 'safari-tp') { signatureIds[testName].safaritp = row.signature_id; } } }); Object.entries(testGroups).forEach(([testName, values]) => { const firefoxAvg = values.firefox.length > 0 ? values.firefox.reduce((a, b) => a + b) / values.firefox.length : 0; const chromeAvg = values.chrome.length > 0 ? values.chrome.reduce((a, b) => a + b) / values.chrome.length : 0; const carAvg = values.car.length > 0 ? values.car.reduce((a, b) => a + b) / values.car.length : 0; const safariAvg = values.safari.length > 0 ? values.safari.reduce((a, b) => a + b) / values.safari.length : 0; const safariTpAvg = values.safaritp.length > 0 ? values.safaritp.reduce((a, b) => a + b) / values.safaritp.length : 0; // Get signature IDs for this test const sigs = signatureIds[testName] || { firefox: 0, chrome: 0, car: 0, safari: 0, safaritp: 0 }; function percentDiff(other, firefox) { return other > 0 ? ((other - firefox) / other) * 100 : 0; } // Calculate differences let chromeDiff = percentDiff(chromeAvg, firefoxAvg); let carDiff = percentDiff(carAvg, firefoxAvg); let safariDiff = percentDiff(safariAvg, firefoxAvg); let safariTpDiff = percentDiff(safariTpAvg, firefoxAvg); if (testName === 'score') { chromeDiff = -chromeDiff; carDiff = -carDiff; safariDiff = -safariDiff; safariTpDiff = -safariTpDiff; } const unit = testName === 'score' ? '' : ' ms'; let row = '<tr onClick="openTestComparison(' + sigs.firefox + ', ' + sigs.chrome + ', ' + sigs.car + ', ' + sigs.safari + ', ' + sigs.safaritp + ')"><th scope="row" class="testName">' + testName + '</th>'; row += '<td>' + (firefoxAvg > 0 ? round(firefoxAvg, 2) + unit : '') + '</td>'; row += '<td>' + (chromeAvg > 0 ? round(chromeAvg, 2) + unit : '') + '</td>'; row += '<td>' + (carAvg > 0 ? round(carAvg, 2) + unit : '') + '</td>'; if (platform.includes('macosx')) { row += '<td>' + (safariAvg > 0 ? round(safariAvg, 2) + unit : '') + '</td>'; row += '<td>' + (safariTpAvg > 0 ? round(safariTpAvg, 2) + unit : '') + '</td>'; } // For differences, negative means Firefox is worse row += '<td style="color: ' + getDiffColor(chromeDiff) + '">' + (chromeAvg > 0 ? round(chromeDiff, 2) + '%' : '') + '</td>'; row += '<td style="color: ' + getDiffColor(carDiff) + '">' + (carAvg > 0 ? round(carDiff, 2) + '%' : '') + '</td>'; if (platform.includes('macosx')) { row += '<td style="color: ' + getDiffColor(safariDiff) + '">' + (safariAvg > 0 ? round(safariDiff, 2) + '%' : '') + '</td>'; row += '<td style="color: ' + getDiffColor(safariTpDiff) + '">' + (safariTpAvg > 0 ? round(safariTpDiff, 2) + '%' : '') + '</td>'; } row += '</tr>'; tableData.push({ html: row, testName: testName, firefoxAvg: firefoxAvg, chromeAvg: chromeAvg, carAvg: carAvg, safariAvg: safariAvg, safariTpAvg: safariTpAvg, chromeDiff: chromeDiff, carDiff: carDiff, safariDiff: safariDiff, safariTpDiff: safariTpDiff }); }); // Store data globally for sorting globalTableData = tableData; // Sort with score at top, then alphabetically by test name tableData.sort((a, b) => { if (a.testName === 'score') return -1; if (b.testName === 'score') return 1; return a.testName.localeCompare(b.testName); }); // Add rows to table tableData.forEach(row => { tableBody.innerHTML += row.html; }); // Add click event listeners to table headers for sorting addSortListeners(); document.getElementById('timewindow').innerHTML = timeWindow + ' prior'; // Calculate total score using 1-week averages const tableRows = document.querySelectorAll('#tableBodyLikely tr:not(.sumRow)'); let totalFirefox = []; let totalChrome = []; let totalCaR = []; let totalSafari = []; let totalSafariTP = []; // Get all values from the last week for each browser data.query_result.data.rows.forEach(row => { if (row.platform === platform && row.test === 'score') { const rowDate = new Date(row.date); if (rowDate >= oneWeekAgo) { if (row.application === 'firefox' || row.application === 'fenix') { totalFirefox.push(row.value); } else if (row.application === 'chrome' || row.application === 'chrome-m') { totalChrome.push(row.value); } else if (row.application === 'custom-car' || row.application === 'cstm-car-m') { totalCaR.push(row.value); } else if (row.application === 'safari') { totalSafari.push(row.value); } else if (row.application === 'safari-tp') { totalSafariTP.push(row.value); } } } }); // Calculate geometric means const FxGeoMean = totalFirefox.length > 0 ? Math.exp(totalFirefox.reduce((a, b) => a + Math.log(b), 0) / totalFirefox.length) : 0; const ChromeGeoMean = totalChrome.length > 0 ? Math.exp(totalChrome.reduce((a, b) => a + Math.log(b), 0) / totalChrome.length) : 0; const CaRGeoMean = totalCaR.length > 0 ? Math.exp(totalCaR.reduce((a, b) => a + Math.log(b), 0) / totalCaR.length) : 0; const SafariGeoMean = totalSafari.length > 0 ? Math.exp(totalSafari.reduce((a, b) => a + Math.log(b), 0) / totalSafari.length) : 0; const SafariTPGeoMean = totalSafariTP.length > 0 ? Math.exp(totalSafariTP.reduce((a, b) => a + Math.log(b), 0) / totalSafariTP.length) : 0; // Calculate differences for total score const diff = ChromeGeoMean > 0 ? (FxGeoMean - ChromeGeoMean) / ChromeGeoMean * 100 : 0; const CaRdiff = CaRGeoMean > 0 ? (FxGeoMean - CaRGeoMean) / CaRGeoMean * 100 : 0; const Safaridiff = SafariGeoMean > 0 ? (FxGeoMean - SafariGeoMean) / SafariGeoMean * 100 : 0; const SafariTPdiff = SafariTPGeoMean > 0 ? (FxGeoMean - SafariTPGeoMean) / SafariTPGeoMean * 100 : 0; // Create total score row let newLine = '<tr onClick="openTestComparison(0, 0, 0, 0, 0)" class="sumRow"><th scope="row" class="testName">Total Score</th>'; newLine += '<td>' + (FxGeoMean > 0 ? round(FxGeoMean, 2) : '') + '</td>'; newLine += '<td>' + (ChromeGeoMean > 0 ? round(ChromeGeoMean, 2) : '') + '</td>'; newLine += '<td>' + (CaRGeoMean > 0 ? round(CaRGeoMean, 2) : '') + '</td>'; if (platform.includes('macosx')) { newLine += '<td>' + (SafariGeoMean > 0 ? round(SafariGeoMean, 2) : '') + '</td>'; newLine += '<td>' + (SafariTPGeoMean > 0 ? round(SafariTPGeoMean, 2) : '') + '</td>'; } newLine += '<td style="color: ' + getDiffColor(diff) + '">' + (ChromeGeoMean > 0 ? round(diff, 2) + '%' : '') + '</td>'; newLine += '<td style="color: ' + getDiffColor(CaRdiff) + '">' + (CaRGeoMean > 0 ? round(CaRdiff, 2) + '%' : '') + '</td>'; if (platform.includes('macosx')) { newLine += '<td style="color: ' + getDiffColor(Safaridiff) + '">' + (SafariGeoMean > 0 ? round(Safaridiff, 2) + '%' : '') + '</td>'; newLine += '<td style="color: ' + getDiffColor(SafariTPdiff) + '">' + (SafariTPGeoMean > 0 ? round(SafariTPdiff, 2) + '%' : '') + '</td>'; } newLine += '</tr>'; // Store total score row for re-adding after sorting const totalScoreRow = document.createElement('div'); totalScoreRow.id = 'totalScoreRow'; totalScoreRow.innerHTML = newLine; document.getElementById('totalScoreRow')?.remove(); document.body.appendChild(totalScoreRow); totalScoreRow.style.display = 'none'; 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 to add click event listeners to table headers for sorting function addSortListeners() { const headers = document.querySelectorAll('#subtestTable tr:nth-child(2) th'); headers.forEach((header, index) => { header.style.cursor = 'pointer'; let column = null; switch(index) { case 0: column = 'testName'; break; case 1: column = 'firefoxAvg'; break; case 2: column = 'chromeAvg'; break; case 3: column = 'carAvg'; break; case 4: if (platform.includes('macosx')) { column = 'safariAvg'; } else { column = 'chromeDiff'; } break; case 5: if (platform.includes('macosx')) { column = 'safariTpAvg'; } else { column = 'carDiff'; } break; case 6: if (platform.includes('macosx')) { column = 'chromeDiff'; } break; case 7: if (platform.includes('macosx')) { column = 'carDiff'; } break; case 8: if (platform.includes('macosx')) { column = 'safariDiff'; } break; case 9: if (platform.includes('macosx')) { column = 'safariTpDiff'; } break; } if (column) { header.addEventListener('click', () => { sortTable(column); }); } }); } async function generateContent() { 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-s24') { document.getElementById("mobilebutton").style.backgroundColor = "gray"; } else if (searchParams.get('os') == 'android-a55') { document.getElementById("mobilebutton2").style.backgroundColor = "gray"; } else if (searchParams.get('os') == 'android-p6') { document.getElementById("mobilebutton3").style.backgroundColor = "gray"; } else { document.getElementById("winbutton").style = "background-color:gray;"; } const dataUrl = 'https://raw.githubusercontent.com/mozilla/performance-data/refs/heads/main/jetstream-data.json.gz'; try { // Fetch the gzipped file as a binary array buffer const response = await fetch(dataUrl); const compressedData = await response.arrayBuffer(); // Decompress the data using pako const decompressedData = pako.inflate(new Uint8Array(compressedData), { to: 'string' }); // Parse the decompressed string as JSON let data = JSON.parse(decompressedData); // Generate output. displayChart(data); displayTable(data); } catch (error) { console.error('Error loading the JSON file:', error); } } function displayChart(data) { const ctx = document.getElementById('myChart').getContext('2d'); let xyValuesFx = []; let xyValuesChrome = []; let xyValuesCaR = []; let xyValuesSafari = []; let xyValuesSafariTP = []; rows = data.query_result.data.rows.filter(row => row.platform === platform && row.test === 'score'); rows.forEach(function (row) { if (row.application == 'firefox' || row.application == 'fenix') { xyValuesFx.push({ x: row.date, y: row.value }); } if (row.application == 'chrome' || row.application == 'chrome-m') { xyValuesChrome.push({ x: row.date, y: row.value }); } if (row.application == 'custom-car' || row.application == 'cstm-car-m') { xyValuesCaR.push({ x: row.date, y: row.value }); } if (row.application == 'safari') { xyValuesSafari.push({ x: row.date, y: row.value }); } if (row.application == 'safari-tp') { xyValuesSafariTP.push({ x: row.date, y: row.value }); } }); let cfg = { type: "scatter", data: { datasets: [ { label: 'Firefox', pointRadius: 3, pointBackgroundColor: "#FF9500", pointBorderColor: "#000000", pointBorderWidth: 0.5, data: xyValuesFx, trendlineLinear: { colorMin: "#FF9500", colorMax: "#FF9500", lineStyle: "dotted", width: 2 } } ] }, options: { aspectRatio: 1.5, scales: { x: { type: 'time', time: { unit: 'day', tooltipFormat: 'll' }, title: { display: true, text: 'Timestamp' } }, y: { beginAtZero: true, title: { display: true, text: 'Score' } } }, } }; cfg.data.datasets.push({ label: 'Chrome', pointRadius: 3, pointBackgroundColor: "#1DA462", pointBorderColor: "#000000", pointBorderWidth: 0.5, data: xyValuesChrome, trendlineLinear: { colorMin: "#1DA462", colorMax: "#1DA462", lineStyle: "dotted", width: 2 } }); if (xyValuesCaR.length > 0) { cfg.data.datasets.push({ label: 'Chromium-as-Release', pointRadius: 3, pointBackgroundColor: "#2773da", pointBorderColor: "#000000", pointBorderWidth: 0.5, data: xyValuesCaR, trendlineLinear: { colorMin: "#2773da", colorMax: "#2773da", lineStyle: "dotted", width: 2 } }); } if (platform.includes('macosx')) { cfg.data.datasets.push({ label: 'Safari', pointRadius: 3, pointBackgroundColor: "#44444444", pointBorderColor: "#000000", pointBorderWidth: 0.5, data: xyValuesSafari, trendlineLinear: { colorMin: "#44444444", colorMax: "#44444444", lineStyle: "dotted", width: 2 } }); cfg.data.datasets.push({ label: 'Safari TP', pointRadius: 3, pointBackgroundColor: "#777", pointBorderColor: "#44444444", pointBorderWidth: 0.5, data: xyValuesSafariTP, trendlineLinear: { colorMin: "#777", colorMax: "#777", lineStyle: "dotted", width: 2 } }); } timeChart = new Chart("myChart", cfg); } function changeRange(newRange) { if (newRange == 'all') { if (!platforms.includes('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> body { background-color: #f0f0f0; } 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; padding: 8px 12px; } .styled-table th { padding: 8px 12px; } .styled-table td { text-align: right; padding: 8px 12px; } .styled-table .testName { text-align: left; } .tableBody tr { border-bottom: 1px solid #dddddd; } .tableBody .sumRow { border-top: 2px solid black; background-color: #dde5ff !important; font-weight: bold; font-size: 1.1em; } .tableBody .sumRow:hover { background-color: #ccd9ff !important; } /* Score row styling */ .tableBody tr:first-child { background-color: #e8eeff !important; font-size: 1.2em !important; font-weight: bold !important; border-top: 2px solid #c7d1ff !important; border-bottom: 2px solid #c7d1ff !important; } .tableBody tr:first-child:hover { background-color: #f0f3ff !important; } /* Other rows styling */ .tableBody tr:not(:first-child):nth-of-type(odd) { background-color: #f3f3f3; } .tableBody tr:not(:first-child):nth-of-type(even) { background-color: #e3e3e3; } .tableBody tr:not(:first-child):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; } /* Styles for sorted columns */ .sorted-asc, .sorted-desc { background-color: #2952cc !important; } #subtestTable th { cursor: pointer; } </style> </head> <body> <div class="top"> <div class="top-title-container"> <div class="top-title"> <b>moz://a</b> performance portal </div> </div> <a href="https://firefox-source-docs.mozilla.org/performance/reporting_a_performance_problem.html" class="btn" title="Report a Performance Bug"> <i class="fa-solid fa-bug"></i> Report Performance Issue </a> </div> <div class="main-content"> <aside class="main-sidebar" id="main-sidebar"> </aside> <div class="content"> <center> <table class="buttons"> <tr> <td colspan="2" style="height:50px;"><a href="jetstream.html?os=windows" id="winbutton">Windows 11</a></td> <td colspan="2" style="height:50px;"><a href="jetstream.html?os=osx" id="macbutton">Mac OSX (M4)</a></td> <td colspan="2" style="height:50px;"><a href="jetstream.html?os=linux" id="linuxbutton">Linux</a></td> </tr> <!-- JS3 does not currently run on Android. <tr> <td colspan="2" style="height:50px;"><a href="jetstream.html?os=android-s24" id="mobilebutton">Android (S24)</a></td> <td colspan="2" style="height:50px;"><a href="jetstream.html?os=android-a55" id="mobilebutton2">Android (A55)</a></td> <td colspan="2" style="height:50px;"><a href="jetstream.html?os=android-p6" id="mobilebutton3">Android (P6)</a></td> </tr> --> </table> <br> <h3>Current Status (higher is better)</h3> <br> <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> <br> <h3>Breakdown: Jetstream3 Subtests</h3> <table class="styled-table" id="subtestTable"> <col> <col> <colgroup span="2"></colgroup> <col> <colgroup span="2"></colgroup> <col> <thead> <tr> <th rowspan="1"></th> <th colspan="5" scope="colgroup">Total time (Lower is better)<br />1wk moving average</th> <th colspan="4" scope="colgroup">Difference vs Firefox</th> </tr> <tr> <th scope="col">testName</th> <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> </tr> </thead> <tbody class="tableBody" id="tableBodyLikely"> </tbody> </table> </center> </div> <!-- content --> </div> <!-- main-content --> <script src="assets/main-ui.js"></script> </body> </html>