xref: /third_party/node/deps/v8/tools/callstats.html (revision 1cb0ef41)
11cb0ef41Sopenharmony_ci<!DOCTYPE html>
21cb0ef41Sopenharmony_ci<html>
31cb0ef41Sopenharmony_ci<!--
41cb0ef41Sopenharmony_ciCopyright 2016 the V8 project authors. All rights reserved.  Use of this source
51cb0ef41Sopenharmony_cicode is governed by a BSD-style license that can be found in the LICENSE file.
61cb0ef41Sopenharmony_ci-->
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci<head>
91cb0ef41Sopenharmony_ci  <meta charset="utf-8">
101cb0ef41Sopenharmony_ci  <title>V8 Runtime Call Stats Komparator</title>
111cb0ef41Sopenharmony_ci  <link rel="stylesheet" type="text/css" href="system-analyzer/index.css">
121cb0ef41Sopenharmony_ci  <style>
131cb0ef41Sopenharmony_ci    body {
141cb0ef41Sopenharmony_ci      font-family: arial;
151cb0ef41Sopenharmony_ci    }
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci    .panel {
181cb0ef41Sopenharmony_ci      display: none;
191cb0ef41Sopenharmony_ci    }
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci    .loaded .panel {
221cb0ef41Sopenharmony_ci      display: block;
231cb0ef41Sopenharmony_ci    }
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci    .panel.alwaysVisible {
261cb0ef41Sopenharmony_ci      display: inherit !important;
271cb0ef41Sopenharmony_ci    }
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci    .error #inputs {
301cb0ef41Sopenharmony_ci      background-color: var(--error-color);
311cb0ef41Sopenharmony_ci    }
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci    table {
341cb0ef41Sopenharmony_ci      display: table;
351cb0ef41Sopenharmony_ci      border-spacing: 0px;
361cb0ef41Sopenharmony_ci    }
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci    tr {
391cb0ef41Sopenharmony_ci      border-spacing: 0px;
401cb0ef41Sopenharmony_ci      padding: 10px;
411cb0ef41Sopenharmony_ci    }
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    td,
441cb0ef41Sopenharmony_ci    th {
451cb0ef41Sopenharmony_ci      padding: 3px 10px 3px 5px;
461cb0ef41Sopenharmony_ci    }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci    .inline {
491cb0ef41Sopenharmony_ci      display: inline-block;
501cb0ef41Sopenharmony_ci      vertical-align: middle;
511cb0ef41Sopenharmony_ci      margin-right: 10px;
521cb0ef41Sopenharmony_ci    }
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci    .hidden {
551cb0ef41Sopenharmony_ci      display: none;
561cb0ef41Sopenharmony_ci    }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci    .view {
591cb0ef41Sopenharmony_ci      display: table;
601cb0ef41Sopenharmony_ci    }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    .panel-group {
631cb0ef41Sopenharmony_ci      display: grid;
641cb0ef41Sopenharmony_ci      align-content: center;
651cb0ef41Sopenharmony_ci      grid-template-columns: repeat(auto-fill, minmax(500px, 1fr));
661cb0ef41Sopenharmony_ci      grid-auto-flow: row dense;
671cb0ef41Sopenharmony_ci      grid-gap: 10px;
681cb0ef41Sopenharmony_ci      margin-top: 10px;
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci    .column {
721cb0ef41Sopenharmony_ci      display: table-cell;
731cb0ef41Sopenharmony_ci      border-right: 1px black dotted;
741cb0ef41Sopenharmony_ci      min-width: 200px;
751cb0ef41Sopenharmony_ci    }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci    .column .header {
781cb0ef41Sopenharmony_ci      padding: 0 10px 0 10px
791cb0ef41Sopenharmony_ci    }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    #column {
821cb0ef41Sopenharmony_ci      display: none;
831cb0ef41Sopenharmony_ci    }
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    .list {
861cb0ef41Sopenharmony_ci      width: 100%;
871cb0ef41Sopenharmony_ci    }
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    select {
901cb0ef41Sopenharmony_ci      width: 100%
911cb0ef41Sopenharmony_ci    }
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    .list tbody {
941cb0ef41Sopenharmony_ci      cursor: pointer;
951cb0ef41Sopenharmony_ci    }
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci    .list tr:nth-child(even) {
981cb0ef41Sopenharmony_ci      background-color: rgba(0.5, 0.5, 0.5, 0.1);
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci    .list tr.child {
1021cb0ef41Sopenharmony_ci      display: none;
1031cb0ef41Sopenharmony_ci    }
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci    .list tr.child.visible {
1061cb0ef41Sopenharmony_ci      display: table-row;
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci    .list .child .name {
1101cb0ef41Sopenharmony_ci      padding-left: 20px;
1111cb0ef41Sopenharmony_ci    }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci    .list .parent td {
1141cb0ef41Sopenharmony_ci      border-top: 1px solid #AAA;
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci    .list .total {
1181cb0ef41Sopenharmony_ci      font-weight: bold
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci    .list tr.parent.selected,
1221cb0ef41Sopenharmony_ci    .list tr:nth-child(even).selected,
1231cb0ef41Sopenharmony_ci    tr.selected {
1241cb0ef41Sopenharmony_ci      background-color: rgba(0.5, 0.5, 0.5, 0.1);
1251cb0ef41Sopenharmony_ci    }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci    .codeSearch {
1281cb0ef41Sopenharmony_ci      display: block-inline;
1291cb0ef41Sopenharmony_ci      float: right;
1301cb0ef41Sopenharmony_ci      border-radius: 5px;
1311cb0ef41Sopenharmony_ci      background-color: #333;
1321cb0ef41Sopenharmony_ci      width: 1em;
1331cb0ef41Sopenharmony_ci      text-align: center;
1341cb0ef41Sopenharmony_ci    }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci    .list .position {
1371cb0ef41Sopenharmony_ci      text-align: right;
1381cb0ef41Sopenharmony_ci      display: none;
1391cb0ef41Sopenharmony_ci    }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    .list div.toggle {
1421cb0ef41Sopenharmony_ci      cursor: pointer;
1431cb0ef41Sopenharmony_ci    }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci    #column_0 .position {
1461cb0ef41Sopenharmony_ci      display: table-cell;
1471cb0ef41Sopenharmony_ci    }
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci    #column_0 .name {
1501cb0ef41Sopenharmony_ci      display: table-cell;
1511cb0ef41Sopenharmony_ci    }
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci    .list .name {
1541cb0ef41Sopenharmony_ci      display: none;
1551cb0ef41Sopenharmony_ci      white-space: nowrap;
1561cb0ef41Sopenharmony_ci    }
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci    .value {
1591cb0ef41Sopenharmony_ci      text-align: right;
1601cb0ef41Sopenharmony_ci    }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci    .selectedVersion {
1631cb0ef41Sopenharmony_ci      font-weight: bold;
1641cb0ef41Sopenharmony_ci    }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci    #baseline {
1671cb0ef41Sopenharmony_ci      width: auto;
1681cb0ef41Sopenharmony_ci    }
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    .pageDetailTable tbody {
1711cb0ef41Sopenharmony_ci      cursor: pointer
1721cb0ef41Sopenharmony_ci    }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci    .pageDetailTable tfoot td {
1751cb0ef41Sopenharmony_ci      border-top: 1px grey solid;
1761cb0ef41Sopenharmony_ci    }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci    #popover {
1791cb0ef41Sopenharmony_ci      position: absolute;
1801cb0ef41Sopenharmony_ci      transform: translateY(-50%) translateX(40px);
1811cb0ef41Sopenharmony_ci      box-shadow: -2px 10px 44px -10px #000;
1821cb0ef41Sopenharmony_ci      border-radius: 5px;
1831cb0ef41Sopenharmony_ci      z-index: 1;
1841cb0ef41Sopenharmony_ci      background-color: var(--surface-color);
1851cb0ef41Sopenharmony_ci      display: none;
1861cb0ef41Sopenharmony_ci      white-space: nowrap;
1871cb0ef41Sopenharmony_ci    }
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci    #popover table {
1901cb0ef41Sopenharmony_ci      position: relative;
1911cb0ef41Sopenharmony_ci      z-index: 1;
1921cb0ef41Sopenharmony_ci      text-align: right;
1931cb0ef41Sopenharmony_ci      margin: 10px;
1941cb0ef41Sopenharmony_ci    }
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci    #popover td {
1971cb0ef41Sopenharmony_ci      padding: 3px 0px 3px 5px;
1981cb0ef41Sopenharmony_ci      white-space: nowrap;
1991cb0ef41Sopenharmony_ci    }
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci    .popoverArrow {
2021cb0ef41Sopenharmony_ci      background-color: var(--surface-color);
2031cb0ef41Sopenharmony_ci      position: absolute;
2041cb0ef41Sopenharmony_ci      width: 30px;
2051cb0ef41Sopenharmony_ci      height: 30px;
2061cb0ef41Sopenharmony_ci      transform: translateY(-50%)rotate(45deg);
2071cb0ef41Sopenharmony_ci      top: 50%;
2081cb0ef41Sopenharmony_ci      left: -10px;
2091cb0ef41Sopenharmony_ci      z-index: 0;
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci    #popover .name {
2131cb0ef41Sopenharmony_ci      padding: 5px;
2141cb0ef41Sopenharmony_ci      font-weight: bold;
2151cb0ef41Sopenharmony_ci      text-align: center;
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    #popover table .compare {
2191cb0ef41Sopenharmony_ci      display: none
2201cb0ef41Sopenharmony_ci    }
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci    #popover table.compare .compare {
2231cb0ef41Sopenharmony_ci      display: table-cell;
2241cb0ef41Sopenharmony_ci    }
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    #popover .compare .time,
2271cb0ef41Sopenharmony_ci    #popover .compare .version {
2281cb0ef41Sopenharmony_ci      padding-left: 10px;
2291cb0ef41Sopenharmony_ci    }
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci    .diff .hideDiff {
2321cb0ef41Sopenharmony_ci      display: none;
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci    .noDiff .hideNoDiff {
2361cb0ef41Sopenharmony_ci      display: none;
2371cb0ef41Sopenharmony_ci    }
2381cb0ef41Sopenharmony_ci  </style>
2391cb0ef41Sopenharmony_ci  <script src="https://www.gstatic.com/charts/loader.js"></script>
2401cb0ef41Sopenharmony_ci  <script>
2411cb0ef41Sopenharmony_ci    "use strict"
2421cb0ef41Sopenharmony_ci    google.charts.load('current', {
2431cb0ef41Sopenharmony_ci      packages: ['corechart']
2441cb0ef41Sopenharmony_ci    });
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci    // Did anybody say monkeypatching?
2471cb0ef41Sopenharmony_ci    if (!NodeList.prototype.forEach) {
2481cb0ef41Sopenharmony_ci      NodeList.prototype.forEach = function (func) {
2491cb0ef41Sopenharmony_ci        for (let i = 0; i < this.length; i++) {
2501cb0ef41Sopenharmony_ci          func(this[i]);
2511cb0ef41Sopenharmony_ci        }
2521cb0ef41Sopenharmony_ci      }
2531cb0ef41Sopenharmony_ci    }
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci    let versions;
2561cb0ef41Sopenharmony_ci    let pages;
2571cb0ef41Sopenharmony_ci    let selectedPage;
2581cb0ef41Sopenharmony_ci    let baselineVersion;
2591cb0ef41Sopenharmony_ci    let selectedEntry;
2601cb0ef41Sopenharmony_ci    let sortByLabel = false;
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci    // Marker to programatically replace the defaultData.
2631cb0ef41Sopenharmony_ci    let defaultData = /*default-data-start*/ undefined /*default-data-end*/;
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci    function initialize() {
2661cb0ef41Sopenharmony_ci      // Initialize the stats table and toggle lists.
2671cb0ef41Sopenharmony_ci      let original = $("column");
2681cb0ef41Sopenharmony_ci      let viewBody = $("view").querySelector('.panelBody');
2691cb0ef41Sopenharmony_ci      removeAllChildren(viewBody);
2701cb0ef41Sopenharmony_ci      let i = 0;
2711cb0ef41Sopenharmony_ci      versions.forEach((version) => {
2721cb0ef41Sopenharmony_ci        if (!version.enabled) return;
2731cb0ef41Sopenharmony_ci        // add column
2741cb0ef41Sopenharmony_ci        let column = original.cloneNode(true);
2751cb0ef41Sopenharmony_ci        column.id = "column_" + i;
2761cb0ef41Sopenharmony_ci        // Fill in all versions
2771cb0ef41Sopenharmony_ci        let select = column.querySelector(".version");
2781cb0ef41Sopenharmony_ci        select.id = "selectVersion_" + i;
2791cb0ef41Sopenharmony_ci        // add all select options
2801cb0ef41Sopenharmony_ci        versions.forEach((version) => {
2811cb0ef41Sopenharmony_ci          if (!version.enabled) return;
2821cb0ef41Sopenharmony_ci          let option = document.createElement("option");
2831cb0ef41Sopenharmony_ci          option.textContent = version.name;
2841cb0ef41Sopenharmony_ci          option.version = version;
2851cb0ef41Sopenharmony_ci          select.appendChild(option);
2861cb0ef41Sopenharmony_ci        });
2871cb0ef41Sopenharmony_ci        // Fill in all page versions
2881cb0ef41Sopenharmony_ci        select = column.querySelector(".pageVersion");
2891cb0ef41Sopenharmony_ci        select.id = "select_" + i;
2901cb0ef41Sopenharmony_ci        // add all pages
2911cb0ef41Sopenharmony_ci        versions.forEach((version) => {
2921cb0ef41Sopenharmony_ci          if (!version.enabled) return;
2931cb0ef41Sopenharmony_ci          let optgroup = document.createElement("optgroup");
2941cb0ef41Sopenharmony_ci          optgroup.label = version.name;
2951cb0ef41Sopenharmony_ci          optgroup.version = version;
2961cb0ef41Sopenharmony_ci          version.forEachPage((page) => {
2971cb0ef41Sopenharmony_ci            let option = document.createElement("option");
2981cb0ef41Sopenharmony_ci            option.textContent = page.name;
2991cb0ef41Sopenharmony_ci            option.page = page;
3001cb0ef41Sopenharmony_ci            optgroup.appendChild(option);
3011cb0ef41Sopenharmony_ci          });
3021cb0ef41Sopenharmony_ci          select.appendChild(optgroup);
3031cb0ef41Sopenharmony_ci        });
3041cb0ef41Sopenharmony_ci        viewBody.appendChild(column);
3051cb0ef41Sopenharmony_ci        i++;
3061cb0ef41Sopenharmony_ci      });
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci      let select = $('baseline');
3091cb0ef41Sopenharmony_ci      removeAllChildren(select);
3101cb0ef41Sopenharmony_ci      select.appendChild(document.createElement('option'));
3111cb0ef41Sopenharmony_ci      versions.forEach((version) => {
3121cb0ef41Sopenharmony_ci        let option = document.createElement("option");
3131cb0ef41Sopenharmony_ci        option.textContent = version.name;
3141cb0ef41Sopenharmony_ci        option.version = version;
3151cb0ef41Sopenharmony_ci        select.appendChild(option);
3161cb0ef41Sopenharmony_ci      });
3171cb0ef41Sopenharmony_ci      initializeToggleList(versions.versions, $('versionSelector'));
3181cb0ef41Sopenharmony_ci      initializeToggleList(pages.values(), $('pageSelector'));
3191cb0ef41Sopenharmony_ci      initializeToggleList(Group.groups.values(), $('groupSelector'));
3201cb0ef41Sopenharmony_ci    }
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci    function initializeToggleList(items, node) {
3231cb0ef41Sopenharmony_ci      let list = node.querySelector('ul');
3241cb0ef41Sopenharmony_ci      removeAllChildren(list);
3251cb0ef41Sopenharmony_ci      items = Array.from(items);
3261cb0ef41Sopenharmony_ci      items.sort(NameComparator);
3271cb0ef41Sopenharmony_ci      items.forEach((item) => {
3281cb0ef41Sopenharmony_ci        let li = document.createElement('li');
3291cb0ef41Sopenharmony_ci        let checkbox = document.createElement('input');
3301cb0ef41Sopenharmony_ci        checkbox.type = 'checkbox';
3311cb0ef41Sopenharmony_ci        checkbox.checked = item.enabled;
3321cb0ef41Sopenharmony_ci        checkbox.item = item;
3331cb0ef41Sopenharmony_ci        checkbox.addEventListener('click', handleToggleVersionOrPageEnable);
3341cb0ef41Sopenharmony_ci        li.appendChild(checkbox);
3351cb0ef41Sopenharmony_ci        li.appendChild(document.createTextNode(item.name));
3361cb0ef41Sopenharmony_ci        list.appendChild(li);
3371cb0ef41Sopenharmony_ci      });
3381cb0ef41Sopenharmony_ci    }
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci    window.addEventListener('popstate', (event) => {
3411cb0ef41Sopenharmony_ci      popHistoryState(event.state);
3421cb0ef41Sopenharmony_ci    });
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci    function popHistoryState(state) {
3451cb0ef41Sopenharmony_ci      if (!state.version) return false;
3461cb0ef41Sopenharmony_ci      if (!versions) return false;
3471cb0ef41Sopenharmony_ci      let version = versions.getByName(state.version);
3481cb0ef41Sopenharmony_ci      if (!version) return false;
3491cb0ef41Sopenharmony_ci      let page = version.get(state.page);
3501cb0ef41Sopenharmony_ci      if (!page) return false;
3511cb0ef41Sopenharmony_ci      if (!state.entry) {
3521cb0ef41Sopenharmony_ci        showEntry(page.total);
3531cb0ef41Sopenharmony_ci      } else {
3541cb0ef41Sopenharmony_ci        let entry = page.get(state.entry);
3551cb0ef41Sopenharmony_ci        if (!entry) {
3561cb0ef41Sopenharmony_ci          showEntry(page.total);
3571cb0ef41Sopenharmony_ci        } else {
3581cb0ef41Sopenharmony_ci          showEntry(entry);
3591cb0ef41Sopenharmony_ci        }
3601cb0ef41Sopenharmony_ci      }
3611cb0ef41Sopenharmony_ci      return true;
3621cb0ef41Sopenharmony_ci    }
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci    function pushHistoryState() {
3651cb0ef41Sopenharmony_ci      let selection = selectedEntry ? selectedEntry : selectedPage;
3661cb0ef41Sopenharmony_ci      if (!selection) return;
3671cb0ef41Sopenharmony_ci      let state = selection.urlParams();
3681cb0ef41Sopenharmony_ci      // Don't push a history state if it didn't change.
3691cb0ef41Sopenharmony_ci      if (JSON.stringify(window.history.state) === JSON.stringify(state)) return;
3701cb0ef41Sopenharmony_ci      let params = "?";
3711cb0ef41Sopenharmony_ci      for (let pairs of Object.entries(state)) {
3721cb0ef41Sopenharmony_ci        params += encodeURIComponent(pairs[0]) + "=" +
3731cb0ef41Sopenharmony_ci          encodeURIComponent(pairs[1]) + "&";
3741cb0ef41Sopenharmony_ci      }
3751cb0ef41Sopenharmony_ci      window.history.pushState(state, selection.toString(), params);
3761cb0ef41Sopenharmony_ci    }
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci    function showSelectedEntryInPage(page) {
3791cb0ef41Sopenharmony_ci      if (!selectedEntry) return showPage(page);
3801cb0ef41Sopenharmony_ci      let entry = page.get(selectedEntry.name);
3811cb0ef41Sopenharmony_ci      if (!entry) return showPage(page);
3821cb0ef41Sopenharmony_ci      selectEntry(entry);
3831cb0ef41Sopenharmony_ci    }
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci    function showPage(firstPage) {
3861cb0ef41Sopenharmony_ci      let changeSelectedEntry = selectedEntry !== undefined &&
3871cb0ef41Sopenharmony_ci        selectedEntry.page === selectedPage;
3881cb0ef41Sopenharmony_ci      selectedPage = firstPage;
3891cb0ef41Sopenharmony_ci      selectedPage.sort();
3901cb0ef41Sopenharmony_ci      showPageInColumn(firstPage, 0);
3911cb0ef41Sopenharmony_ci      // Show the other versions of this page in the following columns.
3921cb0ef41Sopenharmony_ci      let pageVersions = versions.getPageVersions(firstPage);
3931cb0ef41Sopenharmony_ci      let index = 1;
3941cb0ef41Sopenharmony_ci      pageVersions.forEach((page) => {
3951cb0ef41Sopenharmony_ci        if (page !== firstPage) {
3961cb0ef41Sopenharmony_ci          showPageInColumn(page, index);
3971cb0ef41Sopenharmony_ci          index++;
3981cb0ef41Sopenharmony_ci        }
3991cb0ef41Sopenharmony_ci      });
4001cb0ef41Sopenharmony_ci      if (changeSelectedEntry) {
4011cb0ef41Sopenharmony_ci        showEntryDetail(selectedPage.getEntry(selectedEntry));
4021cb0ef41Sopenharmony_ci      }
4031cb0ef41Sopenharmony_ci      showImpactList(selectedPage);
4041cb0ef41Sopenharmony_ci      pushHistoryState();
4051cb0ef41Sopenharmony_ci    }
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci    function clamp(value, min, max) {
4081cb0ef41Sopenharmony_ci      if (value < min) return min;
4091cb0ef41Sopenharmony_ci      if (value > max) return max;
4101cb0ef41Sopenharmony_ci      return value;
4111cb0ef41Sopenharmony_ci    }
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci    function diffColorFromRatio(ratio) {
4141cb0ef41Sopenharmony_ci      if (ratio == Infinity) {
4151cb0ef41Sopenharmony_ci        return '#ff0000';
4161cb0ef41Sopenharmony_ci      }
4171cb0ef41Sopenharmony_ci      if (ratio == -Infinity) {
4181cb0ef41Sopenharmony_ci        return '#00ff00';
4191cb0ef41Sopenharmony_ci      }
4201cb0ef41Sopenharmony_ci      if (ratio > 1) {
4211cb0ef41Sopenharmony_ci        // ratio > 1: #FFFFFF => #00FF00
4221cb0ef41Sopenharmony_ci        const red = clamp(((ratio - 1) * 255 * 10) | 0, 0, 255);
4231cb0ef41Sopenharmony_ci        const other = (255 - red).toString(16).padStart(2, '0');
4241cb0ef41Sopenharmony_ci        return `#ff${other}${other}`;
4251cb0ef41Sopenharmony_ci      }
4261cb0ef41Sopenharmony_ci      // ratio < 1: #FF0000 => #FFFFFF
4271cb0ef41Sopenharmony_ci      const green = clamp(((1 - ratio) * 255 * 10) | 0, 0, 255);
4281cb0ef41Sopenharmony_ci      const other = (255 - green).toString(16).padStart(2, '0');
4291cb0ef41Sopenharmony_ci      return `#${other}ff${other}`;
4301cb0ef41Sopenharmony_ci    }
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci    function showPageInColumn(page, columnIndex) {
4331cb0ef41Sopenharmony_ci      page.sort();
4341cb0ef41Sopenharmony_ci      let showDiff = columnIndex !== 0;
4351cb0ef41Sopenharmony_ci      if (baselineVersion) showDiff = page.version !== baselineVersion;
4361cb0ef41Sopenharmony_ci      let diffColor = (td, a, b) => { };
4371cb0ef41Sopenharmony_ci      if (showDiff) {
4381cb0ef41Sopenharmony_ci        if (baselineVersion) {
4391cb0ef41Sopenharmony_ci          diffColor = (td, diff, baseline) => {
4401cb0ef41Sopenharmony_ci            if (diff == 0) return;
4411cb0ef41Sopenharmony_ci            const ratio = (baseline + diff) / baseline;
4421cb0ef41Sopenharmony_ci            td.style.color = diffColorFromRatio(ratio);
4431cb0ef41Sopenharmony_ci          };
4441cb0ef41Sopenharmony_ci        } else {
4451cb0ef41Sopenharmony_ci          diffColor = (td, value, reference) => {
4461cb0ef41Sopenharmony_ci            if (value == reference) return;
4471cb0ef41Sopenharmony_ci            const ratio = value / reference;
4481cb0ef41Sopenharmony_ci            td.style.color = diffColorFromRatio(ratio);
4491cb0ef41Sopenharmony_ci          }
4501cb0ef41Sopenharmony_ci        }
4511cb0ef41Sopenharmony_ci      }
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci      let column = $('column_' + columnIndex);
4541cb0ef41Sopenharmony_ci      let select = $('select_' + columnIndex);
4551cb0ef41Sopenharmony_ci      // Find the matching option
4561cb0ef41Sopenharmony_ci      selectOption(select, (i, option) => {
4571cb0ef41Sopenharmony_ci        return option.page == page
4581cb0ef41Sopenharmony_ci      });
4591cb0ef41Sopenharmony_ci      let table = column.querySelector("table");
4601cb0ef41Sopenharmony_ci      let oldTbody = table.querySelector('tbody');
4611cb0ef41Sopenharmony_ci      let tbody = document.createElement('tbody');
4621cb0ef41Sopenharmony_ci      let referencePage = selectedPage;
4631cb0ef41Sopenharmony_ci      page.forEachSorted(selectedPage, (parentEntry, entry, referenceEntry) => {
4641cb0ef41Sopenharmony_ci        let tr = document.createElement('tr');
4651cb0ef41Sopenharmony_ci        tbody.appendChild(tr);
4661cb0ef41Sopenharmony_ci        tr.entry = entry;
4671cb0ef41Sopenharmony_ci        tr.parentEntry = parentEntry;
4681cb0ef41Sopenharmony_ci        tr.className = parentEntry === undefined ? 'parent' : 'child';
4691cb0ef41Sopenharmony_ci        // Don't show entries that do not exist on the current page or if we
4701cb0ef41Sopenharmony_ci        // compare against the current page
4711cb0ef41Sopenharmony_ci        if (entry !== undefined && page.version !== baselineVersion) {
4721cb0ef41Sopenharmony_ci          // If we show a diff, use the baselineVersion as the referenceEntry
4731cb0ef41Sopenharmony_ci          if (baselineVersion !== undefined) {
4741cb0ef41Sopenharmony_ci            let baselineEntry = baselineVersion.getEntry(entry);
4751cb0ef41Sopenharmony_ci            if (baselineEntry !== undefined) referenceEntry = baselineEntry
4761cb0ef41Sopenharmony_ci          }
4771cb0ef41Sopenharmony_ci          if (!parentEntry) {
4781cb0ef41Sopenharmony_ci            let node = td(tr, '<div class="toggle">►</div>', 'position');
4791cb0ef41Sopenharmony_ci            node.firstChild.addEventListener('click', handleToggleGroup);
4801cb0ef41Sopenharmony_ci          } else {
4811cb0ef41Sopenharmony_ci            td(tr, entry.position == 0 ? '' : entry.position, 'position');
4821cb0ef41Sopenharmony_ci          }
4831cb0ef41Sopenharmony_ci          addCodeSearchButton(entry,
4841cb0ef41Sopenharmony_ci            td(tr, entry.name, 'name ' + entry.cssClass()));
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci          diffColor(
4871cb0ef41Sopenharmony_ci            td(tr, ms(entry.time), 'value time'),
4881cb0ef41Sopenharmony_ci            entry.time, referenceEntry.time);
4891cb0ef41Sopenharmony_ci          diffColor(
4901cb0ef41Sopenharmony_ci            td(tr, percent(entry.timePercent), 'value time'),
4911cb0ef41Sopenharmony_ci            entry.time, referenceEntry.time);
4921cb0ef41Sopenharmony_ci          diffColor(
4931cb0ef41Sopenharmony_ci            td(tr, count(entry.count), 'value count'),
4941cb0ef41Sopenharmony_ci            entry.count, referenceEntry.count);
4951cb0ef41Sopenharmony_ci        } else if (baselineVersion !== undefined && referenceEntry &&
4961cb0ef41Sopenharmony_ci          page.version !== baselineVersion) {
4971cb0ef41Sopenharmony_ci          // Show comparison of entry that does not exist on the current page.
4981cb0ef41Sopenharmony_ci          tr.entry = new Entry(0, referenceEntry.name);
4991cb0ef41Sopenharmony_ci          tr.entry.page = page;
5001cb0ef41Sopenharmony_ci          td(tr, '-', 'position');
5011cb0ef41Sopenharmony_ci          td(tr, referenceEntry.name, 'name');
5021cb0ef41Sopenharmony_ci          diffColor(
5031cb0ef41Sopenharmony_ci            td(tr, ms(referenceEntry.time), 'value time'),
5041cb0ef41Sopenharmony_ci            referenceEntry.time, 0);
5051cb0ef41Sopenharmony_ci          diffColor(
5061cb0ef41Sopenharmony_ci            td(tr, percent(referenceEntry.timePercent), 'value time'),
5071cb0ef41Sopenharmony_ci            referenceEntry.timePercent, 0);
5081cb0ef41Sopenharmony_ci          diffColor(
5091cb0ef41Sopenharmony_ci            td(tr, count(referenceEntry.count), 'value count'),
5101cb0ef41Sopenharmony_ci            referenceEntry.count, 0);
5111cb0ef41Sopenharmony_ci        } else {
5121cb0ef41Sopenharmony_ci          // Display empty entry / baseline entry
5131cb0ef41Sopenharmony_ci          let showBaselineEntry = entry !== undefined;
5141cb0ef41Sopenharmony_ci          if (showBaselineEntry) {
5151cb0ef41Sopenharmony_ci            if (!parentEntry) {
5161cb0ef41Sopenharmony_ci              let node = td(tr, '<div class="toggle">►</div>', 'position');
5171cb0ef41Sopenharmony_ci              node.firstChild.addEventListener('click', handleToggleGroup);
5181cb0ef41Sopenharmony_ci            } else {
5191cb0ef41Sopenharmony_ci              td(tr, entry.position == 0 ? '' : entry.position, 'position');
5201cb0ef41Sopenharmony_ci            }
5211cb0ef41Sopenharmony_ci            td(tr, entry.name, 'name');
5221cb0ef41Sopenharmony_ci            td(tr, ms(entry.time, false), 'value time');
5231cb0ef41Sopenharmony_ci            td(tr, percent(entry.timePercent, false), 'value time');
5241cb0ef41Sopenharmony_ci            td(tr, count(entry.count, false), 'value count');
5251cb0ef41Sopenharmony_ci          } else {
5261cb0ef41Sopenharmony_ci            td(tr, '-', 'position');
5271cb0ef41Sopenharmony_ci            td(tr, referenceEntry.name, 'name');
5281cb0ef41Sopenharmony_ci            td(tr, '-', 'value time');
5291cb0ef41Sopenharmony_ci            td(tr, '-', 'value time');
5301cb0ef41Sopenharmony_ci            td(tr, '-', 'value count');
5311cb0ef41Sopenharmony_ci          }
5321cb0ef41Sopenharmony_ci        }
5331cb0ef41Sopenharmony_ci      });
5341cb0ef41Sopenharmony_ci      table.replaceChild(tbody, oldTbody);
5351cb0ef41Sopenharmony_ci      let versionSelect = column.querySelector('select.version');
5361cb0ef41Sopenharmony_ci      selectOption(versionSelect, (index, option) => {
5371cb0ef41Sopenharmony_ci        return option.version == page.version
5381cb0ef41Sopenharmony_ci      });
5391cb0ef41Sopenharmony_ci    }
5401cb0ef41Sopenharmony_ci
5411cb0ef41Sopenharmony_ci    function showEntry(entry) {
5421cb0ef41Sopenharmony_ci      selectEntry(entry, true);
5431cb0ef41Sopenharmony_ci    }
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_ci    function selectEntry(entry, updateSelectedPage) {
5461cb0ef41Sopenharmony_ci      let needsPageSwitch = true;
5471cb0ef41Sopenharmony_ci      if (updateSelectedPage && selectedPage) {
5481cb0ef41Sopenharmony_ci        entry = selectedPage.version.getEntry(entry);
5491cb0ef41Sopenharmony_ci        needsPageSwitch = updateSelectedPage && entry.page != selectedPage;
5501cb0ef41Sopenharmony_ci      }
5511cb0ef41Sopenharmony_ci      let rowIndex = 0;
5521cb0ef41Sopenharmony_ci      // If clicked in the detail row change the first column to that page.
5531cb0ef41Sopenharmony_ci      if (needsPageSwitch) showPage(entry.page);
5541cb0ef41Sopenharmony_ci      let childNodes = $('column_0').querySelector('.list tbody').childNodes;
5551cb0ef41Sopenharmony_ci      for (let i = 0; i < childNodes.length; i++) {
5561cb0ef41Sopenharmony_ci        if (childNodes[i].entry !== undefined &&
5571cb0ef41Sopenharmony_ci          childNodes[i].entry.name == entry.name) {
5581cb0ef41Sopenharmony_ci          rowIndex = i;
5591cb0ef41Sopenharmony_ci          break;
5601cb0ef41Sopenharmony_ci        }
5611cb0ef41Sopenharmony_ci      }
5621cb0ef41Sopenharmony_ci      let firstEntry = childNodes[rowIndex].entry;
5631cb0ef41Sopenharmony_ci      if (rowIndex) {
5641cb0ef41Sopenharmony_ci        if (firstEntry.parent) showGroup(firstEntry.parent);
5651cb0ef41Sopenharmony_ci      }
5661cb0ef41Sopenharmony_ci      // Deselect all
5671cb0ef41Sopenharmony_ci      $('view').querySelectorAll('.list tbody tr').forEach((tr) => {
5681cb0ef41Sopenharmony_ci        toggleCssClass(tr, 'selected', false);
5691cb0ef41Sopenharmony_ci      });
5701cb0ef41Sopenharmony_ci      // Select the entry row
5711cb0ef41Sopenharmony_ci      $('view').querySelectorAll("tbody").forEach((body) => {
5721cb0ef41Sopenharmony_ci        let row = body.childNodes[rowIndex];
5731cb0ef41Sopenharmony_ci        if (!row) return;
5741cb0ef41Sopenharmony_ci        toggleCssClass(row, 'selected', row.entry && row.entry.name ==
5751cb0ef41Sopenharmony_ci          firstEntry.name);
5761cb0ef41Sopenharmony_ci      });
5771cb0ef41Sopenharmony_ci      if (updateSelectedPage && selectedEntry) {
5781cb0ef41Sopenharmony_ci        entry = selectedEntry.page.version.getEntry(entry);
5791cb0ef41Sopenharmony_ci      }
5801cb0ef41Sopenharmony_ci      if (entry !== selectedEntry) {
5811cb0ef41Sopenharmony_ci        selectedEntry = entry;
5821cb0ef41Sopenharmony_ci        showEntryDetail(entry);
5831cb0ef41Sopenharmony_ci      }
5841cb0ef41Sopenharmony_ci    }
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci    function showEntryDetail(entry) {
5871cb0ef41Sopenharmony_ci      showVersionDetails(entry);
5881cb0ef41Sopenharmony_ci      showPageDetails(entry);
5891cb0ef41Sopenharmony_ci      showImpactList(entry.page);
5901cb0ef41Sopenharmony_ci      showGraphs(entry.page);
5911cb0ef41Sopenharmony_ci      pushHistoryState();
5921cb0ef41Sopenharmony_ci    }
5931cb0ef41Sopenharmony_ci
5941cb0ef41Sopenharmony_ci    function showVersionDetails(entry) {
5951cb0ef41Sopenharmony_ci      let table, tbody, entries;
5961cb0ef41Sopenharmony_ci      table = $('versionDetails').querySelector('.versionDetailTable');
5971cb0ef41Sopenharmony_ci      tbody = document.createElement('tbody');
5981cb0ef41Sopenharmony_ci      if (entry !== undefined) {
5991cb0ef41Sopenharmony_ci        $('versionDetails').querySelector('h2 span').textContent =
6001cb0ef41Sopenharmony_ci          entry.name + ' in ' + entry.page.name;
6011cb0ef41Sopenharmony_ci        entries = versions.getPageVersions(entry.page).map(
6021cb0ef41Sopenharmony_ci          (page) => {
6031cb0ef41Sopenharmony_ci            return page.get(entry.name)
6041cb0ef41Sopenharmony_ci          });
6051cb0ef41Sopenharmony_ci        entries.sort((a, b) => {
6061cb0ef41Sopenharmony_ci          return a.time - b.time
6071cb0ef41Sopenharmony_ci        });
6081cb0ef41Sopenharmony_ci        entries.forEach((pageEntry) => {
6091cb0ef41Sopenharmony_ci          if (pageEntry === undefined) return;
6101cb0ef41Sopenharmony_ci          let tr = document.createElement('tr');
6111cb0ef41Sopenharmony_ci          if (pageEntry == entry) tr.className += 'selected';
6121cb0ef41Sopenharmony_ci          tr.entry = pageEntry;
6131cb0ef41Sopenharmony_ci          let isBaselineEntry = pageEntry.page.version == baselineVersion;
6141cb0ef41Sopenharmony_ci          td(tr, pageEntry.page.version.name, 'version');
6151cb0ef41Sopenharmony_ci          td(tr, ms(pageEntry.time, !isBaselineEntry), 'value time');
6161cb0ef41Sopenharmony_ci          td(tr, percent(pageEntry.timePercent, !isBaselineEntry), 'value time');
6171cb0ef41Sopenharmony_ci          td(tr, count(pageEntry.count, !isBaselineEntry), 'value count');
6181cb0ef41Sopenharmony_ci          tbody.appendChild(tr);
6191cb0ef41Sopenharmony_ci        });
6201cb0ef41Sopenharmony_ci      }
6211cb0ef41Sopenharmony_ci      table.replaceChild(tbody, table.querySelector('tbody'));
6221cb0ef41Sopenharmony_ci    }
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci    function showPageDetails(entry) {
6251cb0ef41Sopenharmony_ci      let table, tbody, entries;
6261cb0ef41Sopenharmony_ci      table = $('pageDetail').querySelector('.pageDetailTable');
6271cb0ef41Sopenharmony_ci      tbody = document.createElement('tbody');
6281cb0ef41Sopenharmony_ci      if (entry === undefined) {
6291cb0ef41Sopenharmony_ci        table.replaceChild(tbody, table.querySelector('tbody'));
6301cb0ef41Sopenharmony_ci        return;
6311cb0ef41Sopenharmony_ci      }
6321cb0ef41Sopenharmony_ci      let version = entry.page.version;
6331cb0ef41Sopenharmony_ci      let showDiff = version !== baselineVersion;
6341cb0ef41Sopenharmony_ci      $('pageDetail').querySelector('h2 span').textContent =
6351cb0ef41Sopenharmony_ci        version.name;
6361cb0ef41Sopenharmony_ci      entries = version.pages.map((page) => {
6371cb0ef41Sopenharmony_ci        if (!page.enabled) return;
6381cb0ef41Sopenharmony_ci        return page.get(entry.name)
6391cb0ef41Sopenharmony_ci      });
6401cb0ef41Sopenharmony_ci      entries.sort((a, b) => {
6411cb0ef41Sopenharmony_ci        let cmp = b.timePercent - a.timePercent;
6421cb0ef41Sopenharmony_ci        if (cmp.toFixed(1) == 0) return b.time - a.time;
6431cb0ef41Sopenharmony_ci        return cmp
6441cb0ef41Sopenharmony_ci      });
6451cb0ef41Sopenharmony_ci      entries.forEach((pageEntry) => {
6461cb0ef41Sopenharmony_ci        if (pageEntry === undefined) return;
6471cb0ef41Sopenharmony_ci        let tr = document.createElement('tr');
6481cb0ef41Sopenharmony_ci        if (pageEntry === entry) tr.className += 'selected';
6491cb0ef41Sopenharmony_ci        tr.entry = pageEntry;
6501cb0ef41Sopenharmony_ci        td(tr, pageEntry.page.name, 'name');
6511cb0ef41Sopenharmony_ci        td(tr, ms(pageEntry.time, showDiff), 'value time');
6521cb0ef41Sopenharmony_ci        td(tr, percent(pageEntry.timePercent, showDiff), 'value time');
6531cb0ef41Sopenharmony_ci        td(tr, percent(pageEntry.timePercentPerEntry, showDiff),
6541cb0ef41Sopenharmony_ci          'value time hideNoDiff');
6551cb0ef41Sopenharmony_ci        td(tr, count(pageEntry.count, showDiff), 'value count');
6561cb0ef41Sopenharmony_ci        tbody.appendChild(tr);
6571cb0ef41Sopenharmony_ci      });
6581cb0ef41Sopenharmony_ci      // show the total for all pages
6591cb0ef41Sopenharmony_ci      let tds = table.querySelectorAll('tfoot td');
6601cb0ef41Sopenharmony_ci      tds[1].textContent = ms(entry.getTimeImpact(), showDiff);
6611cb0ef41Sopenharmony_ci      // Only show the percentage total if we are in diff mode:
6621cb0ef41Sopenharmony_ci      tds[2].textContent = percent(entry.getTimePercentImpact(), showDiff);
6631cb0ef41Sopenharmony_ci      tds[3].textContent = '';
6641cb0ef41Sopenharmony_ci      tds[4].textContent = count(entry.getCountImpact(), showDiff);
6651cb0ef41Sopenharmony_ci      table.replaceChild(tbody, table.querySelector('tbody'));
6661cb0ef41Sopenharmony_ci    }
6671cb0ef41Sopenharmony_ci
6681cb0ef41Sopenharmony_ci    function showImpactList(page) {
6691cb0ef41Sopenharmony_ci      let impactView = $('impactView');
6701cb0ef41Sopenharmony_ci      impactView.querySelector('h2 span').textContent = page.version.name;
6711cb0ef41Sopenharmony_ci
6721cb0ef41Sopenharmony_ci      let table = impactView.querySelector('table');
6731cb0ef41Sopenharmony_ci      let tbody = document.createElement('tbody');
6741cb0ef41Sopenharmony_ci      let version = page.version;
6751cb0ef41Sopenharmony_ci      let entries = version.allEntries();
6761cb0ef41Sopenharmony_ci      if (selectedEntry !== undefined && selectedEntry.isGroup) {
6771cb0ef41Sopenharmony_ci        impactView.querySelector('h2 span').textContent += " " + selectedEntry.name;
6781cb0ef41Sopenharmony_ci        entries = entries.filter((entry) => {
6791cb0ef41Sopenharmony_ci          return entry.name == selectedEntry.name ||
6801cb0ef41Sopenharmony_ci            (entry.parent && entry.parent.name == selectedEntry.name)
6811cb0ef41Sopenharmony_ci        });
6821cb0ef41Sopenharmony_ci      }
6831cb0ef41Sopenharmony_ci      let isCompareView = baselineVersion !== undefined;
6841cb0ef41Sopenharmony_ci      entries = entries.filter((entry) => {
6851cb0ef41Sopenharmony_ci        if (isCompareView) {
6861cb0ef41Sopenharmony_ci          let impact = entry.getTimeImpact();
6871cb0ef41Sopenharmony_ci          return impact < -1 || 1 < impact
6881cb0ef41Sopenharmony_ci        }
6891cb0ef41Sopenharmony_ci        return entry.getTimePercentImpact() > 0.01;
6901cb0ef41Sopenharmony_ci      });
6911cb0ef41Sopenharmony_ci      entries = entries.slice(0, 50);
6921cb0ef41Sopenharmony_ci      entries.sort((a, b) => {
6931cb0ef41Sopenharmony_ci        let cmp = b.getTimePercentImpact() - a.getTimePercentImpact();
6941cb0ef41Sopenharmony_ci        if (isCompareView || cmp.toFixed(1) == 0) {
6951cb0ef41Sopenharmony_ci          return b.getTimeImpact() - a.getTimeImpact();
6961cb0ef41Sopenharmony_ci        }
6971cb0ef41Sopenharmony_ci        return cmp
6981cb0ef41Sopenharmony_ci      });
6991cb0ef41Sopenharmony_ci      entries.forEach((entry) => {
7001cb0ef41Sopenharmony_ci        let tr = document.createElement('tr');
7011cb0ef41Sopenharmony_ci        tr.entry = entry;
7021cb0ef41Sopenharmony_ci        td(tr, entry.name, 'name');
7031cb0ef41Sopenharmony_ci        td(tr, ms(entry.getTimeImpact()), 'value time');
7041cb0ef41Sopenharmony_ci        let percentImpact = entry.getTimePercentImpact();
7051cb0ef41Sopenharmony_ci        td(tr, percentImpact > 1000 ? '-' : percent(percentImpact), 'value time');
7061cb0ef41Sopenharmony_ci        let topPages = entry.getPagesByPercentImpact().slice(0, 3)
7071cb0ef41Sopenharmony_ci          .map((each) => {
7081cb0ef41Sopenharmony_ci            return each.name + ' (' + percent(each.getEntry(entry).timePercent) +
7091cb0ef41Sopenharmony_ci              ')'
7101cb0ef41Sopenharmony_ci          });
7111cb0ef41Sopenharmony_ci        td(tr, topPages.join(', '), 'name');
7121cb0ef41Sopenharmony_ci        tbody.appendChild(tr);
7131cb0ef41Sopenharmony_ci      });
7141cb0ef41Sopenharmony_ci      table.replaceChild(tbody, table.querySelector('tbody'));
7151cb0ef41Sopenharmony_ci    }
7161cb0ef41Sopenharmony_ci
7171cb0ef41Sopenharmony_ci    function showGraphs(page) {
7181cb0ef41Sopenharmony_ci      let groups = page.groups.filter(each => each.enabled && !each.isTotal);
7191cb0ef41Sopenharmony_ci      // Sort groups by the biggest impact
7201cb0ef41Sopenharmony_ci      groups.sort((a, b) => b.getTimeImpact() - a.getTimeImpact());
7211cb0ef41Sopenharmony_ci      if (selectedGroup == undefined) {
7221cb0ef41Sopenharmony_ci        selectedGroup = groups[0];
7231cb0ef41Sopenharmony_ci      } else {
7241cb0ef41Sopenharmony_ci        groups = groups.filter(each => each.name != selectedGroup.name);
7251cb0ef41Sopenharmony_ci        if (!selectedGroup.isTotal && selectedGroup.enabled) {
7261cb0ef41Sopenharmony_ci          groups.unshift(selectedGroup);
7271cb0ef41Sopenharmony_ci        }
7281cb0ef41Sopenharmony_ci      }
7291cb0ef41Sopenharmony_ci      // Display graphs delayed for a snappier UI.
7301cb0ef41Sopenharmony_ci      setTimeout(() => {
7311cb0ef41Sopenharmony_ci        showPageVersionGraph(groups, page);
7321cb0ef41Sopenharmony_ci        showPageGraph(groups, page);
7331cb0ef41Sopenharmony_ci        showVersionGraph(groups, page);
7341cb0ef41Sopenharmony_ci      }, 10);
7351cb0ef41Sopenharmony_ci    }
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_ci    function getGraphDataTable(groups, page) {
7381cb0ef41Sopenharmony_ci      let dataTable = new google.visualization.DataTable();
7391cb0ef41Sopenharmony_ci      dataTable.addColumn('string', 'Name');
7401cb0ef41Sopenharmony_ci      groups.forEach(group => {
7411cb0ef41Sopenharmony_ci        let column = dataTable.addColumn('number', group.name.substring(6));
7421cb0ef41Sopenharmony_ci        dataTable.setColumnProperty(column, 'group', group);
7431cb0ef41Sopenharmony_ci        column = dataTable.addColumn({
7441cb0ef41Sopenharmony_ci          role: "annotation"
7451cb0ef41Sopenharmony_ci        });
7461cb0ef41Sopenharmony_ci        dataTable.setColumnProperty(column, 'group', group);
7471cb0ef41Sopenharmony_ci      });
7481cb0ef41Sopenharmony_ci      let column = dataTable.addColumn('number', 'Chart Total');
7491cb0ef41Sopenharmony_ci      dataTable.setColumnProperty(column, 'group', page.total);
7501cb0ef41Sopenharmony_ci      column = dataTable.addColumn({
7511cb0ef41Sopenharmony_ci        role: "annotation"
7521cb0ef41Sopenharmony_ci      });
7531cb0ef41Sopenharmony_ci      dataTable.setColumnProperty(column, 'group', page.total);
7541cb0ef41Sopenharmony_ci      return dataTable;
7551cb0ef41Sopenharmony_ci    }
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci    let selectedGroup;
7581cb0ef41Sopenharmony_ci
7591cb0ef41Sopenharmony_ci    class ChartRow {
7601cb0ef41Sopenharmony_ci      static kSortFirstValueRelative(chartRow) {
7611cb0ef41Sopenharmony_ci        if (selectedGroup?.isTotal) return chartRow.total;
7621cb0ef41Sopenharmony_ci        return chartRow.data[0] / chartRow.total;
7631cb0ef41Sopenharmony_ci      }
7641cb0ef41Sopenharmony_ci
7651cb0ef41Sopenharmony_ci      static kSortByFirstValue(chartRow) {
7661cb0ef41Sopenharmony_ci        if (selectedGroup?.isTotal) return chartRow.total;
7671cb0ef41Sopenharmony_ci        return chartRow.data[0];
7681cb0ef41Sopenharmony_ci      }
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_ci      constructor(linkedPage, label, sortValue_fn, data,
7711cb0ef41Sopenharmony_ci        excludeFromAverage = false) {
7721cb0ef41Sopenharmony_ci        this.linkedPage = linkedPage;
7731cb0ef41Sopenharmony_ci        this.label = label;
7741cb0ef41Sopenharmony_ci        if (!Array.isArray(data)) {
7751cb0ef41Sopenharmony_ci          throw new Error("Provide an Array for data");
7761cb0ef41Sopenharmony_ci        }
7771cb0ef41Sopenharmony_ci        this.data = data;
7781cb0ef41Sopenharmony_ci        this.total = 0;
7791cb0ef41Sopenharmony_ci        for (let i = 0; i < data.length; i++) this.total += data[i];
7801cb0ef41Sopenharmony_ci        this.sortValue = sortValue_fn(this);
7811cb0ef41Sopenharmony_ci        this.excludeFromAverage = excludeFromAverage;
7821cb0ef41Sopenharmony_ci      }
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci      forDataTable(maxRowsTotal) {
7851cb0ef41Sopenharmony_ci        // row = [label, entry1, annotation1, entry2, annotation2, ...]
7861cb0ef41Sopenharmony_ci        const rowData = [this.label];
7871cb0ef41Sopenharmony_ci        const kShowLabelLimit = 0.1;
7881cb0ef41Sopenharmony_ci        const kMinLabelWidth = 80;
7891cb0ef41Sopenharmony_ci        const chartWidth = window.innerWidth - 400;
7901cb0ef41Sopenharmony_ci        // Add value,label pairs
7911cb0ef41Sopenharmony_ci        for (let i = 0; i < this.data.length; i++) {
7921cb0ef41Sopenharmony_ci          const value = this.data[i];
7931cb0ef41Sopenharmony_ci          let label = '';
7941cb0ef41Sopenharmony_ci          // Only show labels for entries that are large enough..
7951cb0ef41Sopenharmony_ci          if (Math.abs(value / maxRowsTotal) * chartWidth > kMinLabelWidth) {
7961cb0ef41Sopenharmony_ci            label = ms(value);
7971cb0ef41Sopenharmony_ci          }
7981cb0ef41Sopenharmony_ci          rowData.push(value, label);
7991cb0ef41Sopenharmony_ci        }
8001cb0ef41Sopenharmony_ci        // Add the total row, with very small negative dummy entry for correct
8011cb0ef41Sopenharmony_ci        // placement of labels in diff view.
8021cb0ef41Sopenharmony_ci        rowData.push(this.total >= 0 ? 0 : -0.000000001, ms(this.total));
8031cb0ef41Sopenharmony_ci        return rowData;
8041cb0ef41Sopenharmony_ci      }
8051cb0ef41Sopenharmony_ci    }
8061cb0ef41Sopenharmony_ci    const collator = new Intl.Collator('en-UK');
8071cb0ef41Sopenharmony_ci
8081cb0ef41Sopenharmony_ci    function setDataTableRows(dataTable, rows) {
8091cb0ef41Sopenharmony_ci      let skippedRows = 0;
8101cb0ef41Sopenharmony_ci      // Always sort by the selected entry (first column after the label)
8111cb0ef41Sopenharmony_ci      if (sortByLabel) {
8121cb0ef41Sopenharmony_ci        rows.sort((a, b) => collator.compare(a.label, b.label));
8131cb0ef41Sopenharmony_ci      } else {
8141cb0ef41Sopenharmony_ci        rows.sort((a, b) => b.sortValue - a.sortValue);
8151cb0ef41Sopenharmony_ci      }
8161cb0ef41Sopenharmony_ci      // Aggregate row data for Average/SUM chart entry:
8171cb0ef41Sopenharmony_ci      const aggregateData = rows[0].data.slice().fill(0);
8181cb0ef41Sopenharmony_ci      let maxTotal = 0;
8191cb0ef41Sopenharmony_ci      for (let i = 0; i < rows.length; i++) {
8201cb0ef41Sopenharmony_ci        const row = rows[i];
8211cb0ef41Sopenharmony_ci        let total = Math.abs(row.total);
8221cb0ef41Sopenharmony_ci        if (total > maxTotal) maxTotal = total;
8231cb0ef41Sopenharmony_ci        if (row.excludeFromAverage) {
8241cb0ef41Sopenharmony_ci          skippedRows++;
8251cb0ef41Sopenharmony_ci          continue
8261cb0ef41Sopenharmony_ci        }
8271cb0ef41Sopenharmony_ci        const chartRowData = row.data;
8281cb0ef41Sopenharmony_ci        for (let j = 0; j < chartRowData.length; j++) {
8291cb0ef41Sopenharmony_ci          aggregateData[j] += chartRowData[j];
8301cb0ef41Sopenharmony_ci        }
8311cb0ef41Sopenharmony_ci      }
8321cb0ef41Sopenharmony_ci      const length = rows.length - skippedRows;
8331cb0ef41Sopenharmony_ci      for (let i = 0; i < aggregateData.length; i++) {
8341cb0ef41Sopenharmony_ci        aggregateData[i] /= rows.length;
8351cb0ef41Sopenharmony_ci      }
8361cb0ef41Sopenharmony_ci      const averageRow = new ChartRow(undefined, 'Average',
8371cb0ef41Sopenharmony_ci        ChartRow.kSortByFirstValue, aggregateData);
8381cb0ef41Sopenharmony_ci      dataTable.addRow(averageRow.forDataTable());
8391cb0ef41Sopenharmony_ci
8401cb0ef41Sopenharmony_ci      rows.forEach(chartRow => {
8411cb0ef41Sopenharmony_ci        let rowIndex = dataTable.addRow(chartRow.forDataTable(maxTotal));
8421cb0ef41Sopenharmony_ci        dataTable.setRowProperty(rowIndex, 'page', chartRow.linkedPage);
8431cb0ef41Sopenharmony_ci      });
8441cb0ef41Sopenharmony_ci    }
8451cb0ef41Sopenharmony_ci
8461cb0ef41Sopenharmony_ci    function showPageVersionGraph(groups, page) {
8471cb0ef41Sopenharmony_ci      let dataTable = getGraphDataTable(groups, page);
8481cb0ef41Sopenharmony_ci      let vs = versions.getPageVersions(page);
8491cb0ef41Sopenharmony_ci      // Calculate the entries for the versions
8501cb0ef41Sopenharmony_ci      const rows = vs.map(page => new ChartRow(
8511cb0ef41Sopenharmony_ci        page, page.version.name, ChartRow.kSortByFirstValue,
8521cb0ef41Sopenharmony_ci        groups.map(group => page.getEntry(group).time),
8531cb0ef41Sopenharmony_ci        page.version === baselineVersion));
8541cb0ef41Sopenharmony_ci      renderGraph(`Versions for ${page.name}`, groups, dataTable, rows,
8551cb0ef41Sopenharmony_ci        'pageVersionGraph', true);
8561cb0ef41Sopenharmony_ci    }
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_ci    function showPageGraph(groups, page) {
8591cb0ef41Sopenharmony_ci      let isDiffView = baselineVersion !== undefined;
8601cb0ef41Sopenharmony_ci      let dataTable = getGraphDataTable(groups, page);
8611cb0ef41Sopenharmony_ci      // Calculate the average row
8621cb0ef41Sopenharmony_ci      // Sort the pages by the selected group.
8631cb0ef41Sopenharmony_ci      let pages = page.version.pages.filter(page => page.enabled);
8641cb0ef41Sopenharmony_ci      // Calculate the entries for the pages
8651cb0ef41Sopenharmony_ci      const rows = pages.map(page => new ChartRow(
8661cb0ef41Sopenharmony_ci        page, page.name,
8671cb0ef41Sopenharmony_ci        isDiffView ?
8681cb0ef41Sopenharmony_ci          ChartRow.kSortByFirstValue : ChartRow.kSortFirstValueRelative,
8691cb0ef41Sopenharmony_ci        groups.map(group => page.getEntry(group).time)));
8701cb0ef41Sopenharmony_ci      renderGraph(`Pages for ${page.version.name}`, groups, dataTable, rows,
8711cb0ef41Sopenharmony_ci        'pageGraph', isDiffView ? true : 'percent');
8721cb0ef41Sopenharmony_ci    }
8731cb0ef41Sopenharmony_ci
8741cb0ef41Sopenharmony_ci    function showVersionGraph(groups, page) {
8751cb0ef41Sopenharmony_ci      let dataTable = getGraphDataTable(groups, page);
8761cb0ef41Sopenharmony_ci      let vs = versions.versions.filter(version => version.enabled);
8771cb0ef41Sopenharmony_ci      // Calculate the entries for the versions
8781cb0ef41Sopenharmony_ci      const rows = vs.map((version) => new ChartRow(
8791cb0ef41Sopenharmony_ci        version.get(page), version.name, ChartRow.kSortByFirstValue,
8801cb0ef41Sopenharmony_ci        groups.map(group => version.getEntry(group).getTimeImpact()),
8811cb0ef41Sopenharmony_ci        version === baselineVersion));
8821cb0ef41Sopenharmony_ci      renderGraph('Versions Total Time over all Pages', groups, dataTable, rows,
8831cb0ef41Sopenharmony_ci        'versionGraph', true);
8841cb0ef41Sopenharmony_ci    }
8851cb0ef41Sopenharmony_ci
8861cb0ef41Sopenharmony_ci    function renderGraph(title, groups, dataTable, rows, id, isStacked) {
8871cb0ef41Sopenharmony_ci      let isDiffView = baselineVersion !== undefined;
8881cb0ef41Sopenharmony_ci      setDataTableRows(dataTable, rows);
8891cb0ef41Sopenharmony_ci      let formatter = new google.visualization.NumberFormat({
8901cb0ef41Sopenharmony_ci        suffix: (isDiffView ? 'msΔ' : 'ms'),
8911cb0ef41Sopenharmony_ci        negativeColor: 'red',
8921cb0ef41Sopenharmony_ci        groupingSymbol: "'"
8931cb0ef41Sopenharmony_ci      });
8941cb0ef41Sopenharmony_ci      for (let i = 1; i < dataTable.getNumberOfColumns(); i++) {
8951cb0ef41Sopenharmony_ci        formatter.format(dataTable, i);
8961cb0ef41Sopenharmony_ci      }
8971cb0ef41Sopenharmony_ci      let height = 85 + 28 * dataTable.getNumberOfRows();
8981cb0ef41Sopenharmony_ci      let options = {
8991cb0ef41Sopenharmony_ci        isStacked: isStacked,
9001cb0ef41Sopenharmony_ci        height: height,
9011cb0ef41Sopenharmony_ci        hAxis: {
9021cb0ef41Sopenharmony_ci          minValue: 0,
9031cb0ef41Sopenharmony_ci          textStyle: {
9041cb0ef41Sopenharmony_ci            fontSize: 14
9051cb0ef41Sopenharmony_ci          }
9061cb0ef41Sopenharmony_ci        },
9071cb0ef41Sopenharmony_ci        vAxis: {
9081cb0ef41Sopenharmony_ci          textStyle: {
9091cb0ef41Sopenharmony_ci            fontSize: 14
9101cb0ef41Sopenharmony_ci          }
9111cb0ef41Sopenharmony_ci        },
9121cb0ef41Sopenharmony_ci        tooltip: {
9131cb0ef41Sopenharmony_ci          textStyle: {
9141cb0ef41Sopenharmony_ci            fontSize: 14
9151cb0ef41Sopenharmony_ci          }
9161cb0ef41Sopenharmony_ci        },
9171cb0ef41Sopenharmony_ci        annotations: {
9181cb0ef41Sopenharmony_ci          textStyle: {
9191cb0ef41Sopenharmony_ci            fontSize: 8
9201cb0ef41Sopenharmony_ci          }
9211cb0ef41Sopenharmony_ci        },
9221cb0ef41Sopenharmony_ci        explorer: {
9231cb0ef41Sopenharmony_ci          actions: ['dragToZoom', 'rightClickToReset'],
9241cb0ef41Sopenharmony_ci          maxZoomIn: 0.01
9251cb0ef41Sopenharmony_ci        },
9261cb0ef41Sopenharmony_ci        legend: {
9271cb0ef41Sopenharmony_ci          position: 'top',
9281cb0ef41Sopenharmony_ci          maxLines: 3,
9291cb0ef41Sopenharmony_ci          textStyle: {
9301cb0ef41Sopenharmony_ci            fontSize: 12
9311cb0ef41Sopenharmony_ci          }
9321cb0ef41Sopenharmony_ci        },
9331cb0ef41Sopenharmony_ci        chartArea: {
9341cb0ef41Sopenharmony_ci          left: 200,
9351cb0ef41Sopenharmony_ci          top: 50
9361cb0ef41Sopenharmony_ci        },
9371cb0ef41Sopenharmony_ci        colors: [
9381cb0ef41Sopenharmony_ci          ...groups.map(each => each.color),
9391cb0ef41Sopenharmony_ci          /* Chart Total */
9401cb0ef41Sopenharmony_ci          "#000000",
9411cb0ef41Sopenharmony_ci        ]
9421cb0ef41Sopenharmony_ci      };
9431cb0ef41Sopenharmony_ci      let parentNode = $(id);
9441cb0ef41Sopenharmony_ci      parentNode.querySelector('h2>span, h3>span').textContent = title;
9451cb0ef41Sopenharmony_ci      let graphNode = parentNode.querySelector('.panelBody');
9461cb0ef41Sopenharmony_ci
9471cb0ef41Sopenharmony_ci      let chart = graphNode.chart;
9481cb0ef41Sopenharmony_ci      if (chart === undefined) {
9491cb0ef41Sopenharmony_ci        chart = graphNode.chart = new google.visualization.BarChart(graphNode);
9501cb0ef41Sopenharmony_ci      } else {
9511cb0ef41Sopenharmony_ci        google.visualization.events.removeAllListeners(chart);
9521cb0ef41Sopenharmony_ci      }
9531cb0ef41Sopenharmony_ci      google.visualization.events.addListener(chart, 'select', selectHandler);
9541cb0ef41Sopenharmony_ci
9551cb0ef41Sopenharmony_ci      function getChartEntry(selection) {
9561cb0ef41Sopenharmony_ci        if (!selection) return undefined;
9571cb0ef41Sopenharmony_ci        let column = selection.column;
9581cb0ef41Sopenharmony_ci        if (column == undefined) return undefined;
9591cb0ef41Sopenharmony_ci        let selectedGroup = dataTable.getColumnProperty(column, 'group');
9601cb0ef41Sopenharmony_ci        let row = selection.row;
9611cb0ef41Sopenharmony_ci        if (row == null) return selectedGroup;
9621cb0ef41Sopenharmony_ci        let page = dataTable.getRowProperty(row, 'page');
9631cb0ef41Sopenharmony_ci        if (!page) return selectedGroup;
9641cb0ef41Sopenharmony_ci        return page.getEntry(selectedGroup);
9651cb0ef41Sopenharmony_ci      }
9661cb0ef41Sopenharmony_ci
9671cb0ef41Sopenharmony_ci      function selectHandler(e) {
9681cb0ef41Sopenharmony_ci        const newSelectedGroup = getChartEntry(chart.getSelection()[0]);
9691cb0ef41Sopenharmony_ci        if (newSelectedGroup == selectedGroup) {
9701cb0ef41Sopenharmony_ci          sortByLabel = !sortByLabel;
9711cb0ef41Sopenharmony_ci        } else if (newSelectedGroup === undefined && selectedPage) {
9721cb0ef41Sopenharmony_ci          sortByLabel = true;
9731cb0ef41Sopenharmony_ci          return showGraphs(selectedPage);
9741cb0ef41Sopenharmony_ci        } else {
9751cb0ef41Sopenharmony_ci          sortByLabel = false;
9761cb0ef41Sopenharmony_ci        }
9771cb0ef41Sopenharmony_ci        selectedGroup = newSelectedGroup;
9781cb0ef41Sopenharmony_ci        selectEntry(selectedGroup, true);
9791cb0ef41Sopenharmony_ci      }
9801cb0ef41Sopenharmony_ci
9811cb0ef41Sopenharmony_ci      // Make our global tooltips work
9821cb0ef41Sopenharmony_ci      google.visualization.events.addListener(chart, 'onmouseover', mouseOverHandler);
9831cb0ef41Sopenharmony_ci
9841cb0ef41Sopenharmony_ci      function mouseOverHandler(selection) {
9851cb0ef41Sopenharmony_ci        const selectedGroup = getChartEntry(selection);
9861cb0ef41Sopenharmony_ci        graphNode.entry = selectedGroup;
9871cb0ef41Sopenharmony_ci      }
9881cb0ef41Sopenharmony_ci      chart.draw(dataTable, options);
9891cb0ef41Sopenharmony_ci    }
9901cb0ef41Sopenharmony_ci
9911cb0ef41Sopenharmony_ci    function showGroup(entry) {
9921cb0ef41Sopenharmony_ci      toggleGroup(entry, true);
9931cb0ef41Sopenharmony_ci    }
9941cb0ef41Sopenharmony_ci
9951cb0ef41Sopenharmony_ci    function toggleGroup(group, show) {
9961cb0ef41Sopenharmony_ci      $('view').querySelectorAll(".child").forEach((tr) => {
9971cb0ef41Sopenharmony_ci        let entry = tr.parentEntry;
9981cb0ef41Sopenharmony_ci        if (!entry) return;
9991cb0ef41Sopenharmony_ci        if (entry.name !== group.name) return;
10001cb0ef41Sopenharmony_ci        toggleCssClass(tr, 'visible', show);
10011cb0ef41Sopenharmony_ci      });
10021cb0ef41Sopenharmony_ci    }
10031cb0ef41Sopenharmony_ci
10041cb0ef41Sopenharmony_ci    function showPopover(entry) {
10051cb0ef41Sopenharmony_ci      let popover = $('popover');
10061cb0ef41Sopenharmony_ci      popover.querySelector('td.name').textContent = entry.name;
10071cb0ef41Sopenharmony_ci      popover.querySelector('td.page').textContent = entry.page.name;
10081cb0ef41Sopenharmony_ci      setPopoverDetail(popover, entry, '');
10091cb0ef41Sopenharmony_ci      popover.querySelector('table').className = "";
10101cb0ef41Sopenharmony_ci      if (baselineVersion !== undefined) {
10111cb0ef41Sopenharmony_ci        entry = baselineVersion.getEntry(entry);
10121cb0ef41Sopenharmony_ci        setPopoverDetail(popover, entry, '.compare');
10131cb0ef41Sopenharmony_ci        popover.querySelector('table').className = "compare";
10141cb0ef41Sopenharmony_ci      }
10151cb0ef41Sopenharmony_ci    }
10161cb0ef41Sopenharmony_ci
10171cb0ef41Sopenharmony_ci    function setPopoverDetail(popover, entry, prefix) {
10181cb0ef41Sopenharmony_ci      let node = (name) => popover.querySelector(prefix + name);
10191cb0ef41Sopenharmony_ci      if (entry == undefined) {
10201cb0ef41Sopenharmony_ci        node('.version').textContent = baselineVersion.name;
10211cb0ef41Sopenharmony_ci        node('.time').textContent = '-';
10221cb0ef41Sopenharmony_ci        node('.timeVariance').textContent = '-';
10231cb0ef41Sopenharmony_ci        node('.percent').textContent = '-';
10241cb0ef41Sopenharmony_ci        node('.percentPerEntry').textContent = '-';
10251cb0ef41Sopenharmony_ci        node('.percentVariance').textContent = '-';
10261cb0ef41Sopenharmony_ci        node('.count').textContent = '-';
10271cb0ef41Sopenharmony_ci        node('.countVariance').textContent = '-';
10281cb0ef41Sopenharmony_ci        node('.timeImpact').textContent = '-';
10291cb0ef41Sopenharmony_ci        node('.timePercentImpact').textContent = '-';
10301cb0ef41Sopenharmony_ci      } else {
10311cb0ef41Sopenharmony_ci        node('.version').textContent = entry.page.version.name;
10321cb0ef41Sopenharmony_ci        node('.time').textContent = ms(entry._time, false);
10331cb0ef41Sopenharmony_ci        node('.timeVariance').textContent = percent(entry.timeVariancePercent, false);
10341cb0ef41Sopenharmony_ci        node('.percent').textContent = percent(entry.timePercent, false);
10351cb0ef41Sopenharmony_ci        node('.percentPerEntry').textContent = percent(entry.timePercentPerEntry, false);
10361cb0ef41Sopenharmony_ci        node('.percentVariance').textContent = percent(entry.timePercentVariancePercent, false);
10371cb0ef41Sopenharmony_ci        node('.count').textContent = count(entry._count, false);
10381cb0ef41Sopenharmony_ci        node('.countVariance').textContent = percent(entry.timeVariancePercent, false);
10391cb0ef41Sopenharmony_ci        node('.timeImpact').textContent = ms(entry.getTimeImpact(false), false);
10401cb0ef41Sopenharmony_ci        node('.timePercentImpact').textContent = percent(entry.getTimeImpactVariancePercent(false), false);
10411cb0ef41Sopenharmony_ci      }
10421cb0ef41Sopenharmony_ci    }
10431cb0ef41Sopenharmony_ci  </script>
10441cb0ef41Sopenharmony_ci  <script>
10451cb0ef41Sopenharmony_ci    "use strict"
10461cb0ef41Sopenharmony_ci    // =========================================================================
10471cb0ef41Sopenharmony_ci    // Helpers
10481cb0ef41Sopenharmony_ci    function $(id) {
10491cb0ef41Sopenharmony_ci      return document.getElementById(id)
10501cb0ef41Sopenharmony_ci    }
10511cb0ef41Sopenharmony_ci
10521cb0ef41Sopenharmony_ci    function removeAllChildren(node) {
10531cb0ef41Sopenharmony_ci      while (node.firstChild) {
10541cb0ef41Sopenharmony_ci        node.removeChild(node.firstChild);
10551cb0ef41Sopenharmony_ci      }
10561cb0ef41Sopenharmony_ci    }
10571cb0ef41Sopenharmony_ci
10581cb0ef41Sopenharmony_ci    function selectOption(select, match) {
10591cb0ef41Sopenharmony_ci      let options = select.options;
10601cb0ef41Sopenharmony_ci      for (let i = 0; i < options.length; i++) {
10611cb0ef41Sopenharmony_ci        if (match(i, options[i])) {
10621cb0ef41Sopenharmony_ci          select.selectedIndex = i;
10631cb0ef41Sopenharmony_ci          return;
10641cb0ef41Sopenharmony_ci        }
10651cb0ef41Sopenharmony_ci      }
10661cb0ef41Sopenharmony_ci    }
10671cb0ef41Sopenharmony_ci
10681cb0ef41Sopenharmony_ci    function addCodeSearchButton(entry, node) {
10691cb0ef41Sopenharmony_ci      if (entry.isGroup) return;
10701cb0ef41Sopenharmony_ci      let button = document.createElement("div");
10711cb0ef41Sopenharmony_ci      button.textContent = '?'
10721cb0ef41Sopenharmony_ci      button.className = "codeSearch"
10731cb0ef41Sopenharmony_ci      button.addEventListener('click', handleCodeSearch);
10741cb0ef41Sopenharmony_ci      node.appendChild(button);
10751cb0ef41Sopenharmony_ci      return node;
10761cb0ef41Sopenharmony_ci    }
10771cb0ef41Sopenharmony_ci
10781cb0ef41Sopenharmony_ci    function td(tr, content, className) {
10791cb0ef41Sopenharmony_ci      let td = document.createElement("td");
10801cb0ef41Sopenharmony_ci      if (content[0] == '<') {
10811cb0ef41Sopenharmony_ci        td.innerHTML = content;
10821cb0ef41Sopenharmony_ci      } else {
10831cb0ef41Sopenharmony_ci        td.textContent = content;
10841cb0ef41Sopenharmony_ci      }
10851cb0ef41Sopenharmony_ci      td.className = className
10861cb0ef41Sopenharmony_ci      tr.appendChild(td);
10871cb0ef41Sopenharmony_ci      return td
10881cb0ef41Sopenharmony_ci    }
10891cb0ef41Sopenharmony_ci
10901cb0ef41Sopenharmony_ci    function nodeIndex(node) {
10911cb0ef41Sopenharmony_ci      let children = node.parentNode.childNodes,
10921cb0ef41Sopenharmony_ci        i = 0;
10931cb0ef41Sopenharmony_ci      for (; i < children.length; i++) {
10941cb0ef41Sopenharmony_ci        if (children[i] == node) {
10951cb0ef41Sopenharmony_ci          return i;
10961cb0ef41Sopenharmony_ci        }
10971cb0ef41Sopenharmony_ci      }
10981cb0ef41Sopenharmony_ci      return -1;
10991cb0ef41Sopenharmony_ci    }
11001cb0ef41Sopenharmony_ci
11011cb0ef41Sopenharmony_ci    function toggleCssClass(node, cssClass, toggleState = true) {
11021cb0ef41Sopenharmony_ci      let index = -1;
11031cb0ef41Sopenharmony_ci      let classes;
11041cb0ef41Sopenharmony_ci      if (node.className != undefined) {
11051cb0ef41Sopenharmony_ci        classes = node.className.split(' ');
11061cb0ef41Sopenharmony_ci        index = classes.indexOf(cssClass);
11071cb0ef41Sopenharmony_ci      }
11081cb0ef41Sopenharmony_ci      if (index == -1) {
11091cb0ef41Sopenharmony_ci        if (toggleState === false) return;
11101cb0ef41Sopenharmony_ci        node.className += ' ' + cssClass;
11111cb0ef41Sopenharmony_ci        return;
11121cb0ef41Sopenharmony_ci      }
11131cb0ef41Sopenharmony_ci      if (toggleState === true) return;
11141cb0ef41Sopenharmony_ci      classes.splice(index, 1);
11151cb0ef41Sopenharmony_ci      node.className = classes.join(' ');
11161cb0ef41Sopenharmony_ci    }
11171cb0ef41Sopenharmony_ci
11181cb0ef41Sopenharmony_ci    function NameComparator(a, b) {
11191cb0ef41Sopenharmony_ci      if (a.name > b.name) return 1;
11201cb0ef41Sopenharmony_ci      if (a.name < b.name) return -1;
11211cb0ef41Sopenharmony_ci      return 0
11221cb0ef41Sopenharmony_ci    }
11231cb0ef41Sopenharmony_ci
11241cb0ef41Sopenharmony_ci    function diffSign(value, digits, unit, showDiff) {
11251cb0ef41Sopenharmony_ci      if (showDiff === false || baselineVersion == undefined) {
11261cb0ef41Sopenharmony_ci        if (value === undefined) return '';
11271cb0ef41Sopenharmony_ci        return value.toFixed(digits) + unit;
11281cb0ef41Sopenharmony_ci      }
11291cb0ef41Sopenharmony_ci      return (value >= 0 ? '+' : '') + value.toFixed(digits) + unit + 'Δ';
11301cb0ef41Sopenharmony_ci    }
11311cb0ef41Sopenharmony_ci
11321cb0ef41Sopenharmony_ci    function ms(value, showDiff) {
11331cb0ef41Sopenharmony_ci      return diffSign(value, 1, 'ms', showDiff);
11341cb0ef41Sopenharmony_ci    }
11351cb0ef41Sopenharmony_ci
11361cb0ef41Sopenharmony_ci    function count(value, showDiff) {
11371cb0ef41Sopenharmony_ci      return diffSign(value, 0, '#', showDiff);
11381cb0ef41Sopenharmony_ci    }
11391cb0ef41Sopenharmony_ci
11401cb0ef41Sopenharmony_ci    function percent(value, showDiff) {
11411cb0ef41Sopenharmony_ci      return diffSign(value, 1, '%', showDiff);
11421cb0ef41Sopenharmony_ci    }
11431cb0ef41Sopenharmony_ci  </script>
11441cb0ef41Sopenharmony_ci  <script>
11451cb0ef41Sopenharmony_ci    "use strict"
11461cb0ef41Sopenharmony_ci    // =========================================================================
11471cb0ef41Sopenharmony_ci    // EventHandlers
11481cb0ef41Sopenharmony_ci    async function handleBodyLoad() {
11491cb0ef41Sopenharmony_ci      $('uploadInput').focus();
11501cb0ef41Sopenharmony_ci      if (tryLoadDefaultData() || await tryLoadFromURLParams() ||
11511cb0ef41Sopenharmony_ci        await tryLoadDefaultResults()) {
11521cb0ef41Sopenharmony_ci        displayResultsAfterLoading();
11531cb0ef41Sopenharmony_ci      }
11541cb0ef41Sopenharmony_ci    }
11551cb0ef41Sopenharmony_ci
11561cb0ef41Sopenharmony_ci    function tryLoadDefaultData() {
11571cb0ef41Sopenharmony_ci      if (!defaultData) return false;
11581cb0ef41Sopenharmony_ci      handleLoadJSON(defaultData);
11591cb0ef41Sopenharmony_ci      return true;
11601cb0ef41Sopenharmony_ci    }
11611cb0ef41Sopenharmony_ci
11621cb0ef41Sopenharmony_ci    async function tryLoadFromURLParams() {
11631cb0ef41Sopenharmony_ci      let params = new URLSearchParams(document.location.search);
11641cb0ef41Sopenharmony_ci      let hasFile = false;
11651cb0ef41Sopenharmony_ci      params.forEach(async (value, key) => {
11661cb0ef41Sopenharmony_ci        if (key !== 'file') return;
11671cb0ef41Sopenharmony_ci        hasFile ||= await tryLoadFile(value, true);
11681cb0ef41Sopenharmony_ci      });
11691cb0ef41Sopenharmony_ci      return hasFile;
11701cb0ef41Sopenharmony_ci    }
11711cb0ef41Sopenharmony_ci
11721cb0ef41Sopenharmony_ci    async function tryLoadDefaultResults() {
11731cb0ef41Sopenharmony_ci      if (window.location.protocol === 'file:') return false;
11741cb0ef41Sopenharmony_ci      // Try to load a results.json file adjacent to this day.
11751cb0ef41Sopenharmony_ci      // The markers on the following line can be used to replace the url easily
11761cb0ef41Sopenharmony_ci      // with scripts.
11771cb0ef41Sopenharmony_ci      const url = /*results-url-start*/ 'results.json' /*results-url-end*/;
11781cb0ef41Sopenharmony_ci      return tryLoadFile(url);
11791cb0ef41Sopenharmony_ci    }
11801cb0ef41Sopenharmony_ci
11811cb0ef41Sopenharmony_ci    async function tryLoadFile(url, append = false) {
11821cb0ef41Sopenharmony_ci      if (!url.startsWith('http')) {
11831cb0ef41Sopenharmony_ci        // hack to get relative urls
11841cb0ef41Sopenharmony_ci        let location = window.location;
11851cb0ef41Sopenharmony_ci        let parts = location.pathname.split("/").slice(0, -1);
11861cb0ef41Sopenharmony_ci        url = location.origin + parts.join('/') + '/' + url;
11871cb0ef41Sopenharmony_ci      }
11881cb0ef41Sopenharmony_ci      let response = await fetch(url);
11891cb0ef41Sopenharmony_ci      if (!response.ok) return false;
11901cb0ef41Sopenharmony_ci      let filename = url.split('/');
11911cb0ef41Sopenharmony_ci      filename = filename[filename.length - 1];
11921cb0ef41Sopenharmony_ci      handleLoadText(await response.text(), append, filename);
11931cb0ef41Sopenharmony_ci      return true;
11941cb0ef41Sopenharmony_ci    }
11951cb0ef41Sopenharmony_ci
11961cb0ef41Sopenharmony_ci    function handleAppendFiles() {
11971cb0ef41Sopenharmony_ci      let files = document.getElementById("appendInput").files;
11981cb0ef41Sopenharmony_ci      loadFiles(files, true);
11991cb0ef41Sopenharmony_ci    }
12001cb0ef41Sopenharmony_ci
12011cb0ef41Sopenharmony_ci    function handleLoadFiles() {
12021cb0ef41Sopenharmony_ci      let files = document.getElementById("uploadInput").files;
12031cb0ef41Sopenharmony_ci      loadFiles(files, false)
12041cb0ef41Sopenharmony_ci    }
12051cb0ef41Sopenharmony_ci
12061cb0ef41Sopenharmony_ci    async function loadFiles(files, append) {
12071cb0ef41Sopenharmony_ci      for (let i = 0; i < files.length; i++) {
12081cb0ef41Sopenharmony_ci        const file = files[i];
12091cb0ef41Sopenharmony_ci        console.log(file.name);
12101cb0ef41Sopenharmony_ci        let text = await new Promise((resolve, reject) => {
12111cb0ef41Sopenharmony_ci          const reader = new FileReader();
12121cb0ef41Sopenharmony_ci          reader.onload = () => resolve(reader.result)
12131cb0ef41Sopenharmony_ci          reader.readAsText(file);
12141cb0ef41Sopenharmony_ci        });
12151cb0ef41Sopenharmony_ci        handleLoadText(text, append, file.name);
12161cb0ef41Sopenharmony_ci        // Only the first file might clear existing data, all sequent files
12171cb0ef41Sopenharmony_ci        // are always append.
12181cb0ef41Sopenharmony_ci        append = true;
12191cb0ef41Sopenharmony_ci      }
12201cb0ef41Sopenharmony_ci      displayResultsAfterLoading();
12211cb0ef41Sopenharmony_ci      toggleCssClass(document.body, "loaded");
12221cb0ef41Sopenharmony_ci    }
12231cb0ef41Sopenharmony_ci
12241cb0ef41Sopenharmony_ci    function handleLoadText(text, append, fileName) {
12251cb0ef41Sopenharmony_ci      if (fileName.endsWith('.json')) {
12261cb0ef41Sopenharmony_ci        handleLoadJSON(JSON.parse(text), append, fileName);
12271cb0ef41Sopenharmony_ci      } else if (fileName.endsWith('.csv') ||
12281cb0ef41Sopenharmony_ci        fileName.endsWith('.output') || fileName.endsWith('.output.txt')) {
12291cb0ef41Sopenharmony_ci        handleLoadCSV(text, append, fileName);
12301cb0ef41Sopenharmony_ci      } else if (fileName.endsWith('.txt')) {
12311cb0ef41Sopenharmony_ci        handleLoadTXT(text, append, fileName);
12321cb0ef41Sopenharmony_ci      } else {
12331cb0ef41Sopenharmony_ci        alert(`Unsupported file extension: "${fileName}"`);
12341cb0ef41Sopenharmony_ci      }
12351cb0ef41Sopenharmony_ci    }
12361cb0ef41Sopenharmony_ci
12371cb0ef41Sopenharmony_ci    function getStateFromParams() {
12381cb0ef41Sopenharmony_ci      let query = window.location.search.substr(1);
12391cb0ef41Sopenharmony_ci      let result = {};
12401cb0ef41Sopenharmony_ci      query.split("&").forEach((part) => {
12411cb0ef41Sopenharmony_ci        let item = part.split("=");
12421cb0ef41Sopenharmony_ci        let key = decodeURIComponent(item[0])
12431cb0ef41Sopenharmony_ci        result[key] = decodeURIComponent(item[1]);
12441cb0ef41Sopenharmony_ci      });
12451cb0ef41Sopenharmony_ci      return result;
12461cb0ef41Sopenharmony_ci    }
12471cb0ef41Sopenharmony_ci
12481cb0ef41Sopenharmony_ci    function handleLoadJSON(json, append, fileName) {
12491cb0ef41Sopenharmony_ci      json = fixClusterTelemetryResults(json);
12501cb0ef41Sopenharmony_ci      json = fixTraceImportJSON(json);
12511cb0ef41Sopenharmony_ci      json = fixSingleVersionJSON(json, fileName);
12521cb0ef41Sopenharmony_ci      let isFirstLoad = pages === undefined;
12531cb0ef41Sopenharmony_ci      if (append && !isFirstLoad) {
12541cb0ef41Sopenharmony_ci        json = createUniqueVersions(json);
12551cb0ef41Sopenharmony_ci      }
12561cb0ef41Sopenharmony_ci      if (!append || isFirstLoad) {
12571cb0ef41Sopenharmony_ci        pages = new Pages();
12581cb0ef41Sopenharmony_ci        versions = Versions.fromJSON(json);
12591cb0ef41Sopenharmony_ci      } else {
12601cb0ef41Sopenharmony_ci        Versions.fromJSON(json).forEach(e => versions.add(e))
12611cb0ef41Sopenharmony_ci      }
12621cb0ef41Sopenharmony_ci    }
12631cb0ef41Sopenharmony_ci
12641cb0ef41Sopenharmony_ci    function handleLoadCSV(csv, append, fileName) {
12651cb0ef41Sopenharmony_ci      let isFirstLoad = pages === undefined;
12661cb0ef41Sopenharmony_ci      if (!append || isFirstLoad) {
12671cb0ef41Sopenharmony_ci        pages = new Pages();
12681cb0ef41Sopenharmony_ci        versions = new Versions();
12691cb0ef41Sopenharmony_ci      }
12701cb0ef41Sopenharmony_ci      const lines = csv.split(/\r?\n/);
12711cb0ef41Sopenharmony_ci      // The first line contains only the field names.
12721cb0ef41Sopenharmony_ci      const fields = new Map();
12731cb0ef41Sopenharmony_ci      csvSplit(lines[0]).forEach((name, index) => {
12741cb0ef41Sopenharmony_ci        fields.set(name, index);
12751cb0ef41Sopenharmony_ci      });
12761cb0ef41Sopenharmony_ci      if (fields.has('displayLabel') && fields.has('stories')) {
12771cb0ef41Sopenharmony_ci        handleLoadResultCSV(fields, lines);
12781cb0ef41Sopenharmony_ci      } else if (fields.has('page_name')) {
12791cb0ef41Sopenharmony_ci        handleLoadClusterTelemetryCSV(fields, lines, fileName);
12801cb0ef41Sopenharmony_ci      } else {
12811cb0ef41Sopenharmony_ci        return alert("Unknown CSV format");
12821cb0ef41Sopenharmony_ci      }
12831cb0ef41Sopenharmony_ci    }
12841cb0ef41Sopenharmony_ci
12851cb0ef41Sopenharmony_ci    function csvSplit(line) {
12861cb0ef41Sopenharmony_ci      let fields = [];
12871cb0ef41Sopenharmony_ci      let index = 0;
12881cb0ef41Sopenharmony_ci      while (index < line.length) {
12891cb0ef41Sopenharmony_ci        let lastIndex = index;
12901cb0ef41Sopenharmony_ci        if (line[lastIndex] == '"') {
12911cb0ef41Sopenharmony_ci          index = line.indexOf('"', lastIndex + 1);
12921cb0ef41Sopenharmony_ci          if (index < 0) index = line.length;
12931cb0ef41Sopenharmony_ci          fields.push(line.substring(lastIndex + 1, index));
12941cb0ef41Sopenharmony_ci          // Consume ','
12951cb0ef41Sopenharmony_ci          index++;
12961cb0ef41Sopenharmony_ci        } else {
12971cb0ef41Sopenharmony_ci          index = line.indexOf(',', lastIndex);
12981cb0ef41Sopenharmony_ci          if (index === -1) index = line.length;
12991cb0ef41Sopenharmony_ci          fields.push(line.substring(lastIndex, index))
13001cb0ef41Sopenharmony_ci        }
13011cb0ef41Sopenharmony_ci        // Consume ','
13021cb0ef41Sopenharmony_ci        index++;
13031cb0ef41Sopenharmony_ci      }
13041cb0ef41Sopenharmony_ci      return fields;
13051cb0ef41Sopenharmony_ci    }
13061cb0ef41Sopenharmony_ci
13071cb0ef41Sopenharmony_ci    // Ignore the following categories as they are aggregated values and are
13081cb0ef41Sopenharmony_ci    // created by callstats.html on the fly.
13091cb0ef41Sopenharmony_ci    const import_skip_categories = new Set([
13101cb0ef41Sopenharmony_ci      'V8-Only', 'V8-Only-Main-Thread', 'Total-Main-Thread', 'Blink_Total'
13111cb0ef41Sopenharmony_ci    ])
13121cb0ef41Sopenharmony_ci
13131cb0ef41Sopenharmony_ci    function handleLoadClusterTelemetryCSV(fields, lines, fileName) {
13141cb0ef41Sopenharmony_ci      const rscFields = Array.from(fields.keys())
13151cb0ef41Sopenharmony_ci        .filter(field => {
13161cb0ef41Sopenharmony_ci          return field.endsWith(':duration (ms)') &&
13171cb0ef41Sopenharmony_ci            !import_skip_categories.has(field.split(':')[0])
13181cb0ef41Sopenharmony_ci        })
13191cb0ef41Sopenharmony_ci        .map(field => {
13201cb0ef41Sopenharmony_ci          let name = field.split(':')[0];
13211cb0ef41Sopenharmony_ci          return [name, fields.get(field), fields.get(`${name}:count`)];
13221cb0ef41Sopenharmony_ci        })
13231cb0ef41Sopenharmony_ci      const page_name_i = fields.get('page_name');
13241cb0ef41Sopenharmony_ci      const version = versions.getOrCreate(fileName);
13251cb0ef41Sopenharmony_ci      for (let i = 1; i < lines.length; i++) {
13261cb0ef41Sopenharmony_ci        const line = csvSplit(lines[i]);
13271cb0ef41Sopenharmony_ci        if (line.length == 0) continue;
13281cb0ef41Sopenharmony_ci        let page_name = line[page_name_i];
13291cb0ef41Sopenharmony_ci        if (page_name === undefined) continue;
13301cb0ef41Sopenharmony_ci        page_name = page_name.split(' ')[0];
13311cb0ef41Sopenharmony_ci        const pageVersion = version.getOrCreate(page_name);
13321cb0ef41Sopenharmony_ci        for (let [fieldName, duration_i, count_i] of rscFields) {
13331cb0ef41Sopenharmony_ci          const duration = Number.parseFloat(line[duration_i]);
13341cb0ef41Sopenharmony_ci          const count = Number.parseFloat(line[count_i]);
13351cb0ef41Sopenharmony_ci          // Skip over entries without metrics (most likely crashes)
13361cb0ef41Sopenharmony_ci          if (Number.isNaN(count) || Number.isNaN(duration)) {
13371cb0ef41Sopenharmony_ci            console.warn(`BROKEN ${page_name}`, lines[i])
13381cb0ef41Sopenharmony_ci            break;
13391cb0ef41Sopenharmony_ci          }
13401cb0ef41Sopenharmony_ci          pageVersion.add(new Entry(0, fieldName, duration, 0, 0, count, 0, 0))
13411cb0ef41Sopenharmony_ci        }
13421cb0ef41Sopenharmony_ci      }
13431cb0ef41Sopenharmony_ci    }
13441cb0ef41Sopenharmony_ci
13451cb0ef41Sopenharmony_ci    function handleLoadResultCSV(fields, lines) {
13461cb0ef41Sopenharmony_ci      const version_i = fields.get('displayLabel');
13471cb0ef41Sopenharmony_ci      const page_i = fields.get('stories');
13481cb0ef41Sopenharmony_ci      const category_i = fields.get('name');
13491cb0ef41Sopenharmony_ci      const value_i = fields.get('avg');
13501cb0ef41Sopenharmony_ci      const tempEntriesCache = new Map();
13511cb0ef41Sopenharmony_ci      for (let i = 1; i < lines.length; i++) {
13521cb0ef41Sopenharmony_ci        const line = csvSplit(lines[i]);
13531cb0ef41Sopenharmony_ci        if (line.length == 0) continue;
13541cb0ef41Sopenharmony_ci        const raw_category = line[category_i];
13551cb0ef41Sopenharmony_ci        if (!raw_category.endsWith(':duration') &&
13561cb0ef41Sopenharmony_ci          !raw_category.endsWith(':count')) {
13571cb0ef41Sopenharmony_ci          continue;
13581cb0ef41Sopenharmony_ci        }
13591cb0ef41Sopenharmony_ci        let [category, type] = raw_category.split(':');
13601cb0ef41Sopenharmony_ci        if (import_skip_categories.has(category)) continue;
13611cb0ef41Sopenharmony_ci        const version = versions.getOrCreate(line[version_i]);
13621cb0ef41Sopenharmony_ci        const pageVersion = version.getOrCreate(line[page_i]);
13631cb0ef41Sopenharmony_ci        const value = Number.parseFloat(line[value_i]);
13641cb0ef41Sopenharmony_ci        const entry = TempEntry.get(tempEntriesCache, pageVersion, category);
13651cb0ef41Sopenharmony_ci        if (type == 'duration') {
13661cb0ef41Sopenharmony_ci          entry.durations.push(value)
13671cb0ef41Sopenharmony_ci        } else {
13681cb0ef41Sopenharmony_ci          entry.counts.push(value)
13691cb0ef41Sopenharmony_ci        }
13701cb0ef41Sopenharmony_ci      }
13711cb0ef41Sopenharmony_ci
13721cb0ef41Sopenharmony_ci      tempEntriesCache.forEach((tempEntries, pageVersion) => {
13731cb0ef41Sopenharmony_ci        tempEntries.forEach(tmpEntry => {
13741cb0ef41Sopenharmony_ci          pageVersion.add(tmpEntry.toEntry())
13751cb0ef41Sopenharmony_ci        })
13761cb0ef41Sopenharmony_ci      });
13771cb0ef41Sopenharmony_ci    }
13781cb0ef41Sopenharmony_ci
13791cb0ef41Sopenharmony_ci    class TempEntry {
13801cb0ef41Sopenharmony_ci      constructor(category) {
13811cb0ef41Sopenharmony_ci        this.category = category;
13821cb0ef41Sopenharmony_ci        this.durations = [];
13831cb0ef41Sopenharmony_ci        this.counts = [];
13841cb0ef41Sopenharmony_ci      }
13851cb0ef41Sopenharmony_ci
13861cb0ef41Sopenharmony_ci      static get(cache, pageVersion, category) {
13871cb0ef41Sopenharmony_ci        let tempEntries = cache.get(pageVersion);
13881cb0ef41Sopenharmony_ci        if (tempEntries === undefined) {
13891cb0ef41Sopenharmony_ci          tempEntries = new Map();
13901cb0ef41Sopenharmony_ci          cache.set(pageVersion, tempEntries);
13911cb0ef41Sopenharmony_ci        }
13921cb0ef41Sopenharmony_ci        let tempEntry = tempEntries.get(category);
13931cb0ef41Sopenharmony_ci        if (tempEntry === undefined) {
13941cb0ef41Sopenharmony_ci          tempEntry = new TempEntry(category);
13951cb0ef41Sopenharmony_ci          tempEntries.set(category, tempEntry);
13961cb0ef41Sopenharmony_ci        }
13971cb0ef41Sopenharmony_ci        return tempEntry;
13981cb0ef41Sopenharmony_ci      }
13991cb0ef41Sopenharmony_ci
14001cb0ef41Sopenharmony_ci      toEntry() {
14011cb0ef41Sopenharmony_ci        const [duration, durationStddev] = this.stats(this.durations);
14021cb0ef41Sopenharmony_ci        const [count, countStddev] = this.stats(this.durations);
14031cb0ef41Sopenharmony_ci        return new Entry(0, this.category,
14041cb0ef41Sopenharmony_ci          duration, durationStddev, 0, count, countStddev, 0)
14051cb0ef41Sopenharmony_ci      }
14061cb0ef41Sopenharmony_ci
14071cb0ef41Sopenharmony_ci      stats(values) {
14081cb0ef41Sopenharmony_ci        let sum = 0;
14091cb0ef41Sopenharmony_ci        for (let i = 0; i < values.length; i++) {
14101cb0ef41Sopenharmony_ci          sum += values[i];
14111cb0ef41Sopenharmony_ci        }
14121cb0ef41Sopenharmony_ci        const avg = sum / values.length;
14131cb0ef41Sopenharmony_ci        let stddevSquared = 0;
14141cb0ef41Sopenharmony_ci        for (let i = 0; i < values.length; i++) {
14151cb0ef41Sopenharmony_ci          const delta = values[i] - avg;
14161cb0ef41Sopenharmony_ci          stddevSquared += delta * delta;
14171cb0ef41Sopenharmony_ci        }
14181cb0ef41Sopenharmony_ci        const stddev = Math.sqrt(stddevSquared / values.length);
14191cb0ef41Sopenharmony_ci        return [avg, stddev];
14201cb0ef41Sopenharmony_ci      }
14211cb0ef41Sopenharmony_ci    }
14221cb0ef41Sopenharmony_ci
14231cb0ef41Sopenharmony_ci    function handleLoadTXT(txt, append, fileName) {
14241cb0ef41Sopenharmony_ci      fileName = window.prompt('Version name:', fileName);
14251cb0ef41Sopenharmony_ci      let isFirstLoad = pages === undefined;
14261cb0ef41Sopenharmony_ci      // Load raw RCS output which contains a single page
14271cb0ef41Sopenharmony_ci      if (!append || isFirstLoad) {
14281cb0ef41Sopenharmony_ci        pages = new Pages();
14291cb0ef41Sopenharmony_ci        versions = new Versions()
14301cb0ef41Sopenharmony_ci      }
14311cb0ef41Sopenharmony_ci      versions.add(Version.fromTXT(fileName, txt));
14321cb0ef41Sopenharmony_ci
14331cb0ef41Sopenharmony_ci    }
14341cb0ef41Sopenharmony_ci
14351cb0ef41Sopenharmony_ci    function displayResultsAfterLoading() {
14361cb0ef41Sopenharmony_ci      const isFirstLoad = pages === undefined;
14371cb0ef41Sopenharmony_ci      let state = getStateFromParams();
14381cb0ef41Sopenharmony_ci      initialize()
14391cb0ef41Sopenharmony_ci      if (isFirstLoad && !popHistoryState(state) && selectedPage) {
14401cb0ef41Sopenharmony_ci        showEntry(selectedPage.total);
14411cb0ef41Sopenharmony_ci        return;
14421cb0ef41Sopenharmony_ci      }
14431cb0ef41Sopenharmony_ci      const page = versions.versions[0].pages[0]
14441cb0ef41Sopenharmony_ci      if (page == undefined) return;
14451cb0ef41Sopenharmony_ci      showPage(page);
14461cb0ef41Sopenharmony_ci      showEntry(page.total);
14471cb0ef41Sopenharmony_ci    }
14481cb0ef41Sopenharmony_ci
14491cb0ef41Sopenharmony_ci    function fixClusterTelemetryResults(json) {
14501cb0ef41Sopenharmony_ci      // Convert CT results to callstats compatible JSON
14511cb0ef41Sopenharmony_ci      // Input:
14521cb0ef41Sopenharmony_ci      // { VERSION_NAME: { PAGE: { METRIC: { "count": {XX}, "duration": {XX} }.. }}.. }
14531cb0ef41Sopenharmony_ci      let firstEntry;
14541cb0ef41Sopenharmony_ci      for (let key in json) {
14551cb0ef41Sopenharmony_ci        firstEntry = json[key];
14561cb0ef41Sopenharmony_ci        break;
14571cb0ef41Sopenharmony_ci      }
14581cb0ef41Sopenharmony_ci      // Return the original JSON if it is not a CT result.
14591cb0ef41Sopenharmony_ci      if (firstEntry.pairs === undefined) return json;
14601cb0ef41Sopenharmony_ci      // The results include already the group totals, remove them by filtering.
14611cb0ef41Sopenharmony_ci      let groupNames = new Set(Array.from(Group.groups.values()).map(e => e.name));
14621cb0ef41Sopenharmony_ci      let result = Object.create(null);
14631cb0ef41Sopenharmony_ci      for (let file_name in json) {
14641cb0ef41Sopenharmony_ci        let entries = [];
14651cb0ef41Sopenharmony_ci        let file_data = json[file_name].pairs;
14661cb0ef41Sopenharmony_ci        for (let name in file_data) {
14671cb0ef41Sopenharmony_ci          if (name != "Total" && groupNames.has(name)) continue;
14681cb0ef41Sopenharmony_ci          let entry = file_data[name];
14691cb0ef41Sopenharmony_ci          let count = entry.count;
14701cb0ef41Sopenharmony_ci          let time = entry.time;
14711cb0ef41Sopenharmony_ci          entries.push([name, time, 0, 0, count, 0, 0]);
14721cb0ef41Sopenharmony_ci        }
14731cb0ef41Sopenharmony_ci        let domain = file_name.split("/").slice(-1)[0];
14741cb0ef41Sopenharmony_ci        result[domain] = entries;
14751cb0ef41Sopenharmony_ci      }
14761cb0ef41Sopenharmony_ci      return {
14771cb0ef41Sopenharmony_ci        __proto__: null,
14781cb0ef41Sopenharmony_ci        ClusterTelemetry: result
14791cb0ef41Sopenharmony_ci      };
14801cb0ef41Sopenharmony_ci    }
14811cb0ef41Sopenharmony_ci
14821cb0ef41Sopenharmony_ci    function fixTraceImportJSON(json) {
14831cb0ef41Sopenharmony_ci      // Fix json file that was created by converting a trace json output
14841cb0ef41Sopenharmony_ci      if (!('telemetry-results' in json)) return json;
14851cb0ef41Sopenharmony_ci      // { telemetry-results: { PAGE:[ { METRIC: [ COUNT TIME ], ... }, ... ]}}
14861cb0ef41Sopenharmony_ci      let version_data = {
14871cb0ef41Sopenharmony_ci        __proto__: null
14881cb0ef41Sopenharmony_ci      };
14891cb0ef41Sopenharmony_ci      json = json["telemetry-results"];
14901cb0ef41Sopenharmony_ci      for (let page_name in json) {
14911cb0ef41Sopenharmony_ci        if (page_name == "placeholder") continue;
14921cb0ef41Sopenharmony_ci        let page_data = {
14931cb0ef41Sopenharmony_ci          __proto__: null,
14941cb0ef41Sopenharmony_ci          Total: {
14951cb0ef41Sopenharmony_ci            duration: {
14961cb0ef41Sopenharmony_ci              average: 0,
14971cb0ef41Sopenharmony_ci              stddev: 0
14981cb0ef41Sopenharmony_ci            },
14991cb0ef41Sopenharmony_ci            count: {
15001cb0ef41Sopenharmony_ci              average: 0,
15011cb0ef41Sopenharmony_ci              stddev: 0
15021cb0ef41Sopenharmony_ci            }
15031cb0ef41Sopenharmony_ci          }
15041cb0ef41Sopenharmony_ci        };
15051cb0ef41Sopenharmony_ci        let page = json[page_name];
15061cb0ef41Sopenharmony_ci        for (let slice of page) {
15071cb0ef41Sopenharmony_ci          for (let metric_name in slice) {
15081cb0ef41Sopenharmony_ci            if (metric_name == "Blink_V8") continue;
15091cb0ef41Sopenharmony_ci            // sum up entries
15101cb0ef41Sopenharmony_ci            if (!(metric_name in page_data)) {
15111cb0ef41Sopenharmony_ci              page_data[metric_name] = {
15121cb0ef41Sopenharmony_ci                duration: {
15131cb0ef41Sopenharmony_ci                  average: 0,
15141cb0ef41Sopenharmony_ci                  stddev: 0
15151cb0ef41Sopenharmony_ci                },
15161cb0ef41Sopenharmony_ci                count: {
15171cb0ef41Sopenharmony_ci                  average: 0,
15181cb0ef41Sopenharmony_ci                  stddev: 0
15191cb0ef41Sopenharmony_ci                }
15201cb0ef41Sopenharmony_ci              }
15211cb0ef41Sopenharmony_ci            }
15221cb0ef41Sopenharmony_ci            let [metric_count, metric_duration] = slice[metric_name]
15231cb0ef41Sopenharmony_ci            let metric = page_data[metric_name];
15241cb0ef41Sopenharmony_ci            const kMicroToMilli = 1 / 1000;
15251cb0ef41Sopenharmony_ci            metric.duration.average += metric_duration * kMicroToMilli;
15261cb0ef41Sopenharmony_ci            metric.count.average += metric_count;
15271cb0ef41Sopenharmony_ci
15281cb0ef41Sopenharmony_ci            if (metric_name.startsWith('Blink_')) continue;
15291cb0ef41Sopenharmony_ci            let total = page_data['Total'];
15301cb0ef41Sopenharmony_ci            total.duration.average += metric_duration * kMicroToMilli;
15311cb0ef41Sopenharmony_ci            total.count.average += metric_count;
15321cb0ef41Sopenharmony_ci          }
15331cb0ef41Sopenharmony_ci        }
15341cb0ef41Sopenharmony_ci        version_data[page_name] = page_data;
15351cb0ef41Sopenharmony_ci      }
15361cb0ef41Sopenharmony_ci      return version_data;
15371cb0ef41Sopenharmony_ci    }
15381cb0ef41Sopenharmony_ci
15391cb0ef41Sopenharmony_ci    function fixSingleVersionJSON(json, name) {
15401cb0ef41Sopenharmony_ci      // Try to detect the single-version case, where we're missing the toplevel
15411cb0ef41Sopenharmony_ci      // version object. The incoming JSON is of the form:
15421cb0ef41Sopenharmony_ci      //   { PAGE: ... , PAGE_2:  }
15431cb0ef41Sopenharmony_ci      // Instead of the default multi-page JSON:
15441cb0ef41Sopenharmony_ci      //    {"Version 1": { "Page 1": ..., ...}, "Version 2": {...}, ...}
15451cb0ef41Sopenharmony_ci      // In this case insert a single "Default" version as top-level entry.
15461cb0ef41Sopenharmony_ci      const  firstProperty = (object) => {
15471cb0ef41Sopenharmony_ci        for (let key in object) return object[key];
15481cb0ef41Sopenharmony_ci      };
15491cb0ef41Sopenharmony_ci      const maybeMetrics = firstProperty(json);
15501cb0ef41Sopenharmony_ci      const maybeMetric = firstProperty(maybeMetrics);
15511cb0ef41Sopenharmony_ci      const tempName = name ? name : new Date().toISOString();
15521cb0ef41Sopenharmony_ci      const getFileName =
15531cb0ef41Sopenharmony_ci          () => window.prompt('Enter a name for the loaded file:', tempName);
15541cb0ef41Sopenharmony_ci      if ('count' in maybeMetric && 'duration' in maybeMetric) {
15551cb0ef41Sopenharmony_ci        return {
15561cb0ef41Sopenharmony_ci          [getFileName()]: json
15571cb0ef41Sopenharmony_ci        }
15581cb0ef41Sopenharmony_ci      }
15591cb0ef41Sopenharmony_ci      // Legacy fallback where the metrics are encoded as arrays:
15601cb0ef41Sopenharmony_ci      //  { PAGE: [[metric_name, ...], [...], ]}
15611cb0ef41Sopenharmony_ci      // Also, make sure we don't have the versioned array-style:
15621cb0ef41Sopenharmony_ci      // { VERSION: { PAGE: [[metric_name, ...], [...], ]}, ...}
15631cb0ef41Sopenharmony_ci      const innerArray = firstProperty(maybeMetrics);
15641cb0ef41Sopenharmony_ci      if (Array.isArray(maybeMetric) && !Array.isArray(innerArray)) {
15651cb0ef41Sopenharmony_ci        return {
15661cb0ef41Sopenharmony_ci          [getFileName()]: json
15671cb0ef41Sopenharmony_ci        }
15681cb0ef41Sopenharmony_ci      }
15691cb0ef41Sopenharmony_ci      return json
15701cb0ef41Sopenharmony_ci    }
15711cb0ef41Sopenharmony_ci
15721cb0ef41Sopenharmony_ci    let appendIndex = 0;
15731cb0ef41Sopenharmony_ci
15741cb0ef41Sopenharmony_ci    function createUniqueVersions(json) {
15751cb0ef41Sopenharmony_ci      // Make sure all toplevel entries are unique names and added properly
15761cb0ef41Sopenharmony_ci      appendIndex++;
15771cb0ef41Sopenharmony_ci      let result = {
15781cb0ef41Sopenharmony_ci        __proto__: null
15791cb0ef41Sopenharmony_ci      }
15801cb0ef41Sopenharmony_ci      for (let key in json) {
15811cb0ef41Sopenharmony_ci        result[key + "_" + appendIndex] = json[key];
15821cb0ef41Sopenharmony_ci      }
15831cb0ef41Sopenharmony_ci      return result
15841cb0ef41Sopenharmony_ci    }
15851cb0ef41Sopenharmony_ci
15861cb0ef41Sopenharmony_ci    function handleCopyToClipboard(event) {
15871cb0ef41Sopenharmony_ci      const names = ["Group", ...versions.versions.map(e => e.name)];
15881cb0ef41Sopenharmony_ci      let result = [names.join("\t")];
15891cb0ef41Sopenharmony_ci      let groups = Array.from(Group.groups.values());
15901cb0ef41Sopenharmony_ci      // Move the total group to the end.
15911cb0ef41Sopenharmony_ci      groups.push(groups.shift())
15921cb0ef41Sopenharmony_ci      groups.forEach(group => {
15931cb0ef41Sopenharmony_ci        let row = [group.name];
15941cb0ef41Sopenharmony_ci        versions.forEach(v => {
15951cb0ef41Sopenharmony_ci          const time = v.pages[0].get("Group-" + group.name)?._time ?? 0;
15961cb0ef41Sopenharmony_ci          row.push(time);
15971cb0ef41Sopenharmony_ci        })
15981cb0ef41Sopenharmony_ci        result.push(row.join("\t"));
15991cb0ef41Sopenharmony_ci      });
16001cb0ef41Sopenharmony_ci      result = result.join("\n");
16011cb0ef41Sopenharmony_ci      navigator.clipboard.writeText(result);
16021cb0ef41Sopenharmony_ci    }
16031cb0ef41Sopenharmony_ci
16041cb0ef41Sopenharmony_ci    function handleToggleGroup(event) {
16051cb0ef41Sopenharmony_ci      let group = event.target.parentNode.parentNode.entry;
16061cb0ef41Sopenharmony_ci      toggleGroup(selectedPage.get(group.name), 'toggle');
16071cb0ef41Sopenharmony_ci    }
16081cb0ef41Sopenharmony_ci
16091cb0ef41Sopenharmony_ci    function handleSelectPage(select, event) {
16101cb0ef41Sopenharmony_ci      let option = select.options[select.selectedIndex];
16111cb0ef41Sopenharmony_ci      if (select.id == "select_0") {
16121cb0ef41Sopenharmony_ci        showSelectedEntryInPage(option.page);
16131cb0ef41Sopenharmony_ci      } else {
16141cb0ef41Sopenharmony_ci        let columnIndex = select.id.split('_')[1];
16151cb0ef41Sopenharmony_ci        showPageInColumn(option.page, columnIndex);
16161cb0ef41Sopenharmony_ci      }
16171cb0ef41Sopenharmony_ci    }
16181cb0ef41Sopenharmony_ci
16191cb0ef41Sopenharmony_ci    function handleSelectVersion(select, event) {
16201cb0ef41Sopenharmony_ci      let option = select.options[select.selectedIndex];
16211cb0ef41Sopenharmony_ci      let version = option.version;
16221cb0ef41Sopenharmony_ci      if (select.id == "selectVersion_0") {
16231cb0ef41Sopenharmony_ci        let page = version.get(selectedPage.name);
16241cb0ef41Sopenharmony_ci        showSelectedEntryInPage(page);
16251cb0ef41Sopenharmony_ci      } else {
16261cb0ef41Sopenharmony_ci        let columnIndex = select.id.split('_')[1];
16271cb0ef41Sopenharmony_ci        let pageSelect = $('select_' + columnIndex);
16281cb0ef41Sopenharmony_ci        let page = pageSelect.options[pageSelect.selectedIndex].page;
16291cb0ef41Sopenharmony_ci        page = version.get(page.name);
16301cb0ef41Sopenharmony_ci        showPageInColumn(page, columnIndex);
16311cb0ef41Sopenharmony_ci      }
16321cb0ef41Sopenharmony_ci    }
16331cb0ef41Sopenharmony_ci
16341cb0ef41Sopenharmony_ci    function handleSelectDetailRow(table, event) {
16351cb0ef41Sopenharmony_ci      if (event.target.tagName != 'TD') return;
16361cb0ef41Sopenharmony_ci      let tr = event.target.parentNode;
16371cb0ef41Sopenharmony_ci      if (tr.tagName != 'TR') return;
16381cb0ef41Sopenharmony_ci      if (tr.entry === undefined) return;
16391cb0ef41Sopenharmony_ci      selectEntry(tr.entry, true);
16401cb0ef41Sopenharmony_ci    }
16411cb0ef41Sopenharmony_ci
16421cb0ef41Sopenharmony_ci    function handleSelectRow(table, event, fromDetail) {
16431cb0ef41Sopenharmony_ci      if (event.target.tagName != 'TD') return;
16441cb0ef41Sopenharmony_ci      let tr = event.target.parentNode;
16451cb0ef41Sopenharmony_ci      if (tr.tagName != 'TR') return;
16461cb0ef41Sopenharmony_ci      if (tr.entry === undefined) return;
16471cb0ef41Sopenharmony_ci      selectEntry(tr.entry, false);
16481cb0ef41Sopenharmony_ci    }
16491cb0ef41Sopenharmony_ci
16501cb0ef41Sopenharmony_ci    function handleSelectBaseline(select, event) {
16511cb0ef41Sopenharmony_ci      let option = select.options[select.selectedIndex];
16521cb0ef41Sopenharmony_ci      baselineVersion = option.version;
16531cb0ef41Sopenharmony_ci      let showingDiff = baselineVersion !== undefined;
16541cb0ef41Sopenharmony_ci      let body = $('body');
16551cb0ef41Sopenharmony_ci      toggleCssClass(body, 'diff', showingDiff);
16561cb0ef41Sopenharmony_ci      toggleCssClass(body, 'noDiff', !showingDiff);
16571cb0ef41Sopenharmony_ci      showPage(selectedPage);
16581cb0ef41Sopenharmony_ci      if (selectedEntry === undefined) return;
16591cb0ef41Sopenharmony_ci      selectEntry(selectedEntry, true);
16601cb0ef41Sopenharmony_ci    }
16611cb0ef41Sopenharmony_ci
16621cb0ef41Sopenharmony_ci    function findEntry(event) {
16631cb0ef41Sopenharmony_ci      let target = event.target;
16641cb0ef41Sopenharmony_ci      while (target.entry === undefined) {
16651cb0ef41Sopenharmony_ci        target = target.parentNode;
16661cb0ef41Sopenharmony_ci        if (!target) return undefined;
16671cb0ef41Sopenharmony_ci      }
16681cb0ef41Sopenharmony_ci      return target.entry;
16691cb0ef41Sopenharmony_ci    }
16701cb0ef41Sopenharmony_ci
16711cb0ef41Sopenharmony_ci    function handleUpdatePopover(event) {
16721cb0ef41Sopenharmony_ci      let popover = $('popover');
16731cb0ef41Sopenharmony_ci      popover.style.left = event.pageX + 'px';
16741cb0ef41Sopenharmony_ci      popover.style.top = event.pageY + 'px';
16751cb0ef41Sopenharmony_ci      popover.style.display = 'none';
16761cb0ef41Sopenharmony_ci      popover.style.display = event.shiftKey ? 'block' : 'none';
16771cb0ef41Sopenharmony_ci      let entry = findEntry(event);
16781cb0ef41Sopenharmony_ci      if (entry === undefined) return;
16791cb0ef41Sopenharmony_ci      showPopover(entry);
16801cb0ef41Sopenharmony_ci    }
16811cb0ef41Sopenharmony_ci
16821cb0ef41Sopenharmony_ci    function handleToggleVersionOrPageEnable(event) {
16831cb0ef41Sopenharmony_ci      let item = this.item;
16841cb0ef41Sopenharmony_ci      if (item === undefined) return;
16851cb0ef41Sopenharmony_ci      item.enabled = this.checked;
16861cb0ef41Sopenharmony_ci      initialize();
16871cb0ef41Sopenharmony_ci      let page = selectedPage;
16881cb0ef41Sopenharmony_ci      if (page === undefined || !page.version.enabled) {
16891cb0ef41Sopenharmony_ci        page = versions.getEnabledPage(page.name);
16901cb0ef41Sopenharmony_ci      }
16911cb0ef41Sopenharmony_ci      if (!page.enabled) {
16921cb0ef41Sopenharmony_ci        page = page.getNextPage();
16931cb0ef41Sopenharmony_ci      }
16941cb0ef41Sopenharmony_ci      showPage(page);
16951cb0ef41Sopenharmony_ci    }
16961cb0ef41Sopenharmony_ci
16971cb0ef41Sopenharmony_ci    function handleCodeSearch(event) {
16981cb0ef41Sopenharmony_ci      let entry = findEntry(event);
16991cb0ef41Sopenharmony_ci      if (entry === undefined) return;
17001cb0ef41Sopenharmony_ci      let url = "https://cs.chromium.org/search/?sq=package:chromium&type=cs&q=";
17011cb0ef41Sopenharmony_ci      name = entry.name;
17021cb0ef41Sopenharmony_ci      if (name.startsWith("API_")) {
17031cb0ef41Sopenharmony_ci        name = name.substring(4);
17041cb0ef41Sopenharmony_ci      }
17051cb0ef41Sopenharmony_ci      url += encodeURIComponent(name) + "+file:src/v8/src";
17061cb0ef41Sopenharmony_ci      window.open(url, '_blank');
17071cb0ef41Sopenharmony_ci    }
17081cb0ef41Sopenharmony_ci  </script>
17091cb0ef41Sopenharmony_ci  <script>
17101cb0ef41Sopenharmony_ci    "use strict"
17111cb0ef41Sopenharmony_ci    // =========================================================================
17121cb0ef41Sopenharmony_ci    class Versions {
17131cb0ef41Sopenharmony_ci      constructor() {
17141cb0ef41Sopenharmony_ci        this.versions = [];
17151cb0ef41Sopenharmony_ci      }
17161cb0ef41Sopenharmony_ci      add(version) {
17171cb0ef41Sopenharmony_ci        this.versions.push(version);
17181cb0ef41Sopenharmony_ci        return version;
17191cb0ef41Sopenharmony_ci      }
17201cb0ef41Sopenharmony_ci      getPageVersions(page) {
17211cb0ef41Sopenharmony_ci        let result = [];
17221cb0ef41Sopenharmony_ci        this.versions.forEach((version) => {
17231cb0ef41Sopenharmony_ci          if (!version.enabled) return;
17241cb0ef41Sopenharmony_ci          let versionPage = version.get(page.name);
17251cb0ef41Sopenharmony_ci          if (versionPage !== undefined) result.push(versionPage);
17261cb0ef41Sopenharmony_ci        });
17271cb0ef41Sopenharmony_ci        return result;
17281cb0ef41Sopenharmony_ci      }
17291cb0ef41Sopenharmony_ci      get length() {
17301cb0ef41Sopenharmony_ci        return this.versions.length
17311cb0ef41Sopenharmony_ci      }
17321cb0ef41Sopenharmony_ci      get(index) {
17331cb0ef41Sopenharmony_ci        return this.versions[index]
17341cb0ef41Sopenharmony_ci      }
17351cb0ef41Sopenharmony_ci      getByName(name) {
17361cb0ef41Sopenharmony_ci        return this.versions.find((each) => each.name == name);
17371cb0ef41Sopenharmony_ci      }
17381cb0ef41Sopenharmony_ci      getOrCreate(name) {
17391cb0ef41Sopenharmony_ci        return this.getByName(name) ?? this.add(new Version(name));
17401cb0ef41Sopenharmony_ci      }
17411cb0ef41Sopenharmony_ci      forEach(f) {
17421cb0ef41Sopenharmony_ci        this.versions.forEach(f);
17431cb0ef41Sopenharmony_ci      }
17441cb0ef41Sopenharmony_ci      sort() {
17451cb0ef41Sopenharmony_ci        this.versions.sort(NameComparator);
17461cb0ef41Sopenharmony_ci      }
17471cb0ef41Sopenharmony_ci      getEnabledPage(name) {
17481cb0ef41Sopenharmony_ci        for (let i = 0; i < this.versions.length; i++) {
17491cb0ef41Sopenharmony_ci          let version = this.versions[i];
17501cb0ef41Sopenharmony_ci          if (!version.enabled) continue;
17511cb0ef41Sopenharmony_ci          let page = version.get(name);
17521cb0ef41Sopenharmony_ci          if (page !== undefined) return page;
17531cb0ef41Sopenharmony_ci        }
17541cb0ef41Sopenharmony_ci      }
17551cb0ef41Sopenharmony_ci
17561cb0ef41Sopenharmony_ci      static fromJSON(json) {
17571cb0ef41Sopenharmony_ci        let versions = new Versions();
17581cb0ef41Sopenharmony_ci        for (let version in json) {
17591cb0ef41Sopenharmony_ci          versions.add(Version.fromJSON(version, json[version]));
17601cb0ef41Sopenharmony_ci        }
17611cb0ef41Sopenharmony_ci        versions.sort();
17621cb0ef41Sopenharmony_ci        return versions;
17631cb0ef41Sopenharmony_ci      }
17641cb0ef41Sopenharmony_ci    }
17651cb0ef41Sopenharmony_ci
17661cb0ef41Sopenharmony_ci    class Version {
17671cb0ef41Sopenharmony_ci      constructor(name) {
17681cb0ef41Sopenharmony_ci        this.name = name;
17691cb0ef41Sopenharmony_ci        this.enabled = true;
17701cb0ef41Sopenharmony_ci        this.pages = [];
17711cb0ef41Sopenharmony_ci      }
17721cb0ef41Sopenharmony_ci      add(page) {
17731cb0ef41Sopenharmony_ci        this.pages.push(page);
17741cb0ef41Sopenharmony_ci        return page;
17751cb0ef41Sopenharmony_ci      }
17761cb0ef41Sopenharmony_ci      indexOf(name) {
17771cb0ef41Sopenharmony_ci        for (let i = 0; i < this.pages.length; i++) {
17781cb0ef41Sopenharmony_ci          if (this.pages[i].name == name) return i;
17791cb0ef41Sopenharmony_ci        }
17801cb0ef41Sopenharmony_ci        return -1;
17811cb0ef41Sopenharmony_ci      }
17821cb0ef41Sopenharmony_ci      getNextPage(page) {
17831cb0ef41Sopenharmony_ci        if (this.length == 0) return undefined;
17841cb0ef41Sopenharmony_ci        return this.pages[(this.indexOf(page.name) + 1) % this.length];
17851cb0ef41Sopenharmony_ci      }
17861cb0ef41Sopenharmony_ci      get(name) {
17871cb0ef41Sopenharmony_ci        let index = this.indexOf(name);
17881cb0ef41Sopenharmony_ci        if (0 <= index) return this.pages[index];
17891cb0ef41Sopenharmony_ci        return undefined;
17901cb0ef41Sopenharmony_ci      }
17911cb0ef41Sopenharmony_ci      getOrCreate(name) {
17921cb0ef41Sopenharmony_ci        return this.get(name) ??
17931cb0ef41Sopenharmony_ci            this.add(new PageVersion(this, pages.getOrCreate(name)));
17941cb0ef41Sopenharmony_ci      }
17951cb0ef41Sopenharmony_ci      get length() {
17961cb0ef41Sopenharmony_ci        return this.pages.length;
17971cb0ef41Sopenharmony_ci      }
17981cb0ef41Sopenharmony_ci      getEntry(entry) {
17991cb0ef41Sopenharmony_ci        if (entry === undefined) return undefined;
18001cb0ef41Sopenharmony_ci        let page = this.get(entry.page.name);
18011cb0ef41Sopenharmony_ci        if (page === undefined) return undefined;
18021cb0ef41Sopenharmony_ci        return page.get(entry.name);
18031cb0ef41Sopenharmony_ci      }
18041cb0ef41Sopenharmony_ci      forEachEntry(fun) {
18051cb0ef41Sopenharmony_ci        this.forEachPage((page) => {
18061cb0ef41Sopenharmony_ci          page.forEach(fun);
18071cb0ef41Sopenharmony_ci        });
18081cb0ef41Sopenharmony_ci      }
18091cb0ef41Sopenharmony_ci      forEachPage(fun) {
18101cb0ef41Sopenharmony_ci        this.pages.forEach((page) => {
18111cb0ef41Sopenharmony_ci          if (!page.enabled) return;
18121cb0ef41Sopenharmony_ci          fun(page);
18131cb0ef41Sopenharmony_ci        })
18141cb0ef41Sopenharmony_ci      }
18151cb0ef41Sopenharmony_ci      allEntries() {
18161cb0ef41Sopenharmony_ci        let map = new Map();
18171cb0ef41Sopenharmony_ci        this.forEachEntry((group, entry) => {
18181cb0ef41Sopenharmony_ci          if (!map.has(entry.name)) map.set(entry.name, entry);
18191cb0ef41Sopenharmony_ci        });
18201cb0ef41Sopenharmony_ci        return Array.from(map.values());
18211cb0ef41Sopenharmony_ci      }
18221cb0ef41Sopenharmony_ci      getTotalValue(name, property) {
18231cb0ef41Sopenharmony_ci        if (name === undefined) name = this.pages[0].total.name;
18241cb0ef41Sopenharmony_ci        let sum = 0;
18251cb0ef41Sopenharmony_ci        this.forEachPage((page) => {
18261cb0ef41Sopenharmony_ci          let entry = page.get(name);
18271cb0ef41Sopenharmony_ci          if (entry !== undefined) sum += entry[property];
18281cb0ef41Sopenharmony_ci        });
18291cb0ef41Sopenharmony_ci        return sum;
18301cb0ef41Sopenharmony_ci      }
18311cb0ef41Sopenharmony_ci      getTotalTime(name, showDiff) {
18321cb0ef41Sopenharmony_ci        return this.getTotalValue(name, showDiff === false ? '_time' : 'time');
18331cb0ef41Sopenharmony_ci      }
18341cb0ef41Sopenharmony_ci      getTotalTimePercent(name, showDiff) {
18351cb0ef41Sopenharmony_ci        if (baselineVersion === undefined || showDiff === false) {
18361cb0ef41Sopenharmony_ci          // Return the overall average percent of the given entry name.
18371cb0ef41Sopenharmony_ci          return this.getTotalValue(name, 'time') /
18381cb0ef41Sopenharmony_ci            this.getTotalTime('Group-Total') * 100;
18391cb0ef41Sopenharmony_ci        }
18401cb0ef41Sopenharmony_ci        // Otherwise return the difference to the sum of the baseline version.
18411cb0ef41Sopenharmony_ci        let baselineValue = baselineVersion.getTotalTime(name, false);
18421cb0ef41Sopenharmony_ci        let total = this.getTotalValue(name, '_time');
18431cb0ef41Sopenharmony_ci        return (total / baselineValue - 1) * 100;
18441cb0ef41Sopenharmony_ci      }
18451cb0ef41Sopenharmony_ci      getTotalTimeVariance(name, showDiff) {
18461cb0ef41Sopenharmony_ci        // Calculate the overall error for a given entry name
18471cb0ef41Sopenharmony_ci        let sum = 0;
18481cb0ef41Sopenharmony_ci        this.forEachPage((page) => {
18491cb0ef41Sopenharmony_ci          let entry = page.get(name);
18501cb0ef41Sopenharmony_ci          if (entry === undefined) return;
18511cb0ef41Sopenharmony_ci          sum += entry.timeVariance * entry.timeVariance;
18521cb0ef41Sopenharmony_ci        });
18531cb0ef41Sopenharmony_ci        return Math.sqrt(sum);
18541cb0ef41Sopenharmony_ci      }
18551cb0ef41Sopenharmony_ci      getTotalTimeVariancePercent(name, showDiff) {
18561cb0ef41Sopenharmony_ci        return this.getTotalTimeVariance(name, showDiff) /
18571cb0ef41Sopenharmony_ci          this.getTotalTime(name, showDiff) * 100;
18581cb0ef41Sopenharmony_ci      }
18591cb0ef41Sopenharmony_ci      getTotalCount(name, showDiff) {
18601cb0ef41Sopenharmony_ci        return this.getTotalValue(name, showDiff === false ? '_count' : 'count');
18611cb0ef41Sopenharmony_ci      }
18621cb0ef41Sopenharmony_ci      getAverageTimeImpact(name, showDiff) {
18631cb0ef41Sopenharmony_ci        return this.getTotalTime(name, showDiff) / this.pages.length;
18641cb0ef41Sopenharmony_ci      }
18651cb0ef41Sopenharmony_ci      getPagesByPercentImpact(name) {
18661cb0ef41Sopenharmony_ci        let sortedPages =
18671cb0ef41Sopenharmony_ci          this.pages.filter((each) => {
18681cb0ef41Sopenharmony_ci            return each.get(name) !== undefined
18691cb0ef41Sopenharmony_ci          });
18701cb0ef41Sopenharmony_ci        sortedPages.sort((a, b) => {
18711cb0ef41Sopenharmony_ci          return b.get(name).timePercent - a.get(name).timePercent;
18721cb0ef41Sopenharmony_ci        });
18731cb0ef41Sopenharmony_ci        return sortedPages;
18741cb0ef41Sopenharmony_ci      }
18751cb0ef41Sopenharmony_ci      sort() {
18761cb0ef41Sopenharmony_ci        this.pages.sort(NameComparator)
18771cb0ef41Sopenharmony_ci      }
18781cb0ef41Sopenharmony_ci
18791cb0ef41Sopenharmony_ci      static fromJSON(name, data) {
18801cb0ef41Sopenharmony_ci        let version = new Version(name);
18811cb0ef41Sopenharmony_ci        for (let pageName in data) {
18821cb0ef41Sopenharmony_ci          version.add(PageVersion.fromJSON(version, pageName, data[pageName]));
18831cb0ef41Sopenharmony_ci        }
18841cb0ef41Sopenharmony_ci        version.sort();
18851cb0ef41Sopenharmony_ci        return version;
18861cb0ef41Sopenharmony_ci      }
18871cb0ef41Sopenharmony_ci
18881cb0ef41Sopenharmony_ci      static fromTXT(name, txt) {
18891cb0ef41Sopenharmony_ci        let version = new Version(name);
18901cb0ef41Sopenharmony_ci        let defaultName = "RAW DATA";
18911cb0ef41Sopenharmony_ci        PageVersion.fromTXT(version, defaultName, txt)
18921cb0ef41Sopenharmony_ci          .forEach(each => version.add(each));
18931cb0ef41Sopenharmony_ci        return version;
18941cb0ef41Sopenharmony_ci      }
18951cb0ef41Sopenharmony_ci    }
18961cb0ef41Sopenharmony_ci
18971cb0ef41Sopenharmony_ci    class Pages extends Map {
18981cb0ef41Sopenharmony_ci      get(name) {
18991cb0ef41Sopenharmony_ci        if (name.indexOf('www.') == 0) {
19001cb0ef41Sopenharmony_ci          name = name.substring(4);
19011cb0ef41Sopenharmony_ci        }
19021cb0ef41Sopenharmony_ci        if (!this.has(name)) {
19031cb0ef41Sopenharmony_ci          this.set(name, new Page(name));
19041cb0ef41Sopenharmony_ci        }
19051cb0ef41Sopenharmony_ci        return super.get(name);
19061cb0ef41Sopenharmony_ci      }
19071cb0ef41Sopenharmony_ci      getOrCreate(name) {
19081cb0ef41Sopenharmony_ci        return this.get(name);
19091cb0ef41Sopenharmony_ci      }
19101cb0ef41Sopenharmony_ci    }
19111cb0ef41Sopenharmony_ci
19121cb0ef41Sopenharmony_ci    class Page {
19131cb0ef41Sopenharmony_ci      constructor(name) {
19141cb0ef41Sopenharmony_ci        this.name = name;
19151cb0ef41Sopenharmony_ci        this.enabled = true;
19161cb0ef41Sopenharmony_ci        this.versions = [];
19171cb0ef41Sopenharmony_ci      }
19181cb0ef41Sopenharmony_ci      add(pageVersion) {
19191cb0ef41Sopenharmony_ci        this.versions.push(pageVersion);
19201cb0ef41Sopenharmony_ci        return pageVersion;
19211cb0ef41Sopenharmony_ci      }
19221cb0ef41Sopenharmony_ci    }
19231cb0ef41Sopenharmony_ci
19241cb0ef41Sopenharmony_ci    class PageVersion {
19251cb0ef41Sopenharmony_ci      constructor(version, page) {
19261cb0ef41Sopenharmony_ci        this.page = page;
19271cb0ef41Sopenharmony_ci        this.page.add(this);
19281cb0ef41Sopenharmony_ci        this.total = Group.groups.get('total').entry();
19291cb0ef41Sopenharmony_ci        this.total.isTotal = true;
19301cb0ef41Sopenharmony_ci        this.unclassified = new UnclassifiedEntry(this)
19311cb0ef41Sopenharmony_ci        this.groups = [
19321cb0ef41Sopenharmony_ci          this.total,
19331cb0ef41Sopenharmony_ci          Group.groups.get('ic').entry(),
19341cb0ef41Sopenharmony_ci          Group.groups.get('optimize-background').entry(),
19351cb0ef41Sopenharmony_ci          Group.groups.get('optimize').entry(),
19361cb0ef41Sopenharmony_ci          Group.groups.get('compile-background').entry(),
19371cb0ef41Sopenharmony_ci          Group.groups.get('compile').entry(),
19381cb0ef41Sopenharmony_ci          Group.groups.get('parse-background').entry(),
19391cb0ef41Sopenharmony_ci          Group.groups.get('parse').entry(),
19401cb0ef41Sopenharmony_ci          Group.groups.get('blink').entry(),
19411cb0ef41Sopenharmony_ci          Group.groups.get('callback').entry(),
19421cb0ef41Sopenharmony_ci          Group.groups.get('api').entry(),
19431cb0ef41Sopenharmony_ci          Group.groups.get('gc-custom').entry(),
19441cb0ef41Sopenharmony_ci          Group.groups.get('gc-background').entry(),
19451cb0ef41Sopenharmony_ci          Group.groups.get('gc').entry(),
19461cb0ef41Sopenharmony_ci          Group.groups.get('javascript').entry(),
19471cb0ef41Sopenharmony_ci          Group.groups.get('websnapshot').entry(),
19481cb0ef41Sopenharmony_ci          Group.groups.get('runtime').entry(),
19491cb0ef41Sopenharmony_ci          this.unclassified
19501cb0ef41Sopenharmony_ci        ];
19511cb0ef41Sopenharmony_ci        this.entryDict = new Map();
19521cb0ef41Sopenharmony_ci        this.groups.forEach((entry) => {
19531cb0ef41Sopenharmony_ci          entry.page = this;
19541cb0ef41Sopenharmony_ci          this.entryDict.set(entry.name, entry);
19551cb0ef41Sopenharmony_ci        });
19561cb0ef41Sopenharmony_ci        this.version = version;
19571cb0ef41Sopenharmony_ci      }
19581cb0ef41Sopenharmony_ci      toString() {
19591cb0ef41Sopenharmony_ci        return this.version.name + ": " + this.name;
19601cb0ef41Sopenharmony_ci      }
19611cb0ef41Sopenharmony_ci      urlParams() {
19621cb0ef41Sopenharmony_ci        return {
19631cb0ef41Sopenharmony_ci          version: this.version.name,
19641cb0ef41Sopenharmony_ci          page: this.name
19651cb0ef41Sopenharmony_ci        };
19661cb0ef41Sopenharmony_ci      }
19671cb0ef41Sopenharmony_ci      add(entry) {
19681cb0ef41Sopenharmony_ci        let existingEntry = this.entryDict.get(entry.name);
19691cb0ef41Sopenharmony_ci        if (existingEntry !== undefined) {
19701cb0ef41Sopenharmony_ci          // Duplicate entries happen when multiple runs are combined into a
19711cb0ef41Sopenharmony_ci          // single file.
19721cb0ef41Sopenharmony_ci          existingEntry.add(entry);
19731cb0ef41Sopenharmony_ci          for (let i = 0; i < this.groups.length; i++) {
19741cb0ef41Sopenharmony_ci            const group = this.groups[i];
19751cb0ef41Sopenharmony_ci            if (group.addTimeAndCount(entry)) return;
19761cb0ef41Sopenharmony_ci          }
19771cb0ef41Sopenharmony_ci        } else {
19781cb0ef41Sopenharmony_ci          // Ignore accidentally added Group entries.
19791cb0ef41Sopenharmony_ci          if (entry.name.startsWith(GroupedEntry.prefix)) {
19801cb0ef41Sopenharmony_ci            console.warn("Skipping accidentally added Group entry:", entry, this);
19811cb0ef41Sopenharmony_ci            return;
19821cb0ef41Sopenharmony_ci          }
19831cb0ef41Sopenharmony_ci          entry.page = this;
19841cb0ef41Sopenharmony_ci          this.entryDict.set(entry.name, entry);
19851cb0ef41Sopenharmony_ci          for (let group of this.groups) {
19861cb0ef41Sopenharmony_ci            if (group.add(entry)) return;
19871cb0ef41Sopenharmony_ci          }
19881cb0ef41Sopenharmony_ci        }
19891cb0ef41Sopenharmony_ci        console.error("Should not get here", entry);
19901cb0ef41Sopenharmony_ci      }
19911cb0ef41Sopenharmony_ci      get(name) {
19921cb0ef41Sopenharmony_ci        return this.entryDict.get(name)
19931cb0ef41Sopenharmony_ci      }
19941cb0ef41Sopenharmony_ci      getEntry(entry) {
19951cb0ef41Sopenharmony_ci        if (entry === undefined) return undefined;
19961cb0ef41Sopenharmony_ci        return this.get(entry.name);
19971cb0ef41Sopenharmony_ci      }
19981cb0ef41Sopenharmony_ci      get length() {
19991cb0ef41Sopenharmony_ci        return this.versions.length
20001cb0ef41Sopenharmony_ci      }
20011cb0ef41Sopenharmony_ci      get name() {
20021cb0ef41Sopenharmony_ci        return this.page.name
20031cb0ef41Sopenharmony_ci      }
20041cb0ef41Sopenharmony_ci      get enabled() {
20051cb0ef41Sopenharmony_ci        return this.page.enabled
20061cb0ef41Sopenharmony_ci      }
20071cb0ef41Sopenharmony_ci      forEachSorted(referencePage, func) {
20081cb0ef41Sopenharmony_ci        // Iterate over all the entries in the order they appear on the
20091cb0ef41Sopenharmony_ci        // reference page.
20101cb0ef41Sopenharmony_ci        referencePage.forEach((parent, referenceEntry) => {
20111cb0ef41Sopenharmony_ci          let entry;
20121cb0ef41Sopenharmony_ci          if (parent) parent = this.entryDict.get(parent.name);
20131cb0ef41Sopenharmony_ci          if (referenceEntry) entry = this.entryDict.get(referenceEntry.name);
20141cb0ef41Sopenharmony_ci          func(parent, entry, referenceEntry);
20151cb0ef41Sopenharmony_ci        });
20161cb0ef41Sopenharmony_ci      }
20171cb0ef41Sopenharmony_ci      forEach(fun) {
20181cb0ef41Sopenharmony_ci        this.forEachGroup((group) => {
20191cb0ef41Sopenharmony_ci          fun(undefined, group);
20201cb0ef41Sopenharmony_ci          group.forEach((entry) => {
20211cb0ef41Sopenharmony_ci            fun(group, entry)
20221cb0ef41Sopenharmony_ci          });
20231cb0ef41Sopenharmony_ci        });
20241cb0ef41Sopenharmony_ci      }
20251cb0ef41Sopenharmony_ci      forEachGroup(fun) {
20261cb0ef41Sopenharmony_ci        this.groups.forEach(fun)
20271cb0ef41Sopenharmony_ci      }
20281cb0ef41Sopenharmony_ci      sort() {
20291cb0ef41Sopenharmony_ci        this.groups.sort((a, b) => {
20301cb0ef41Sopenharmony_ci          return b.time - a.time;
20311cb0ef41Sopenharmony_ci        });
20321cb0ef41Sopenharmony_ci        this.groups.forEach((group) => {
20331cb0ef41Sopenharmony_ci          group.sort()
20341cb0ef41Sopenharmony_ci        });
20351cb0ef41Sopenharmony_ci      }
20361cb0ef41Sopenharmony_ci      distanceFromTotalPercent() {
20371cb0ef41Sopenharmony_ci        let sum = 0;
20381cb0ef41Sopenharmony_ci        this.groups.forEach(group => {
20391cb0ef41Sopenharmony_ci          if (group == this.total) return;
20401cb0ef41Sopenharmony_ci          let value = group.getTimePercentImpact() -
20411cb0ef41Sopenharmony_ci            this.getEntry(group).timePercent;
20421cb0ef41Sopenharmony_ci          sum += value * value;
20431cb0ef41Sopenharmony_ci        });
20441cb0ef41Sopenharmony_ci        return sum;
20451cb0ef41Sopenharmony_ci      }
20461cb0ef41Sopenharmony_ci      getNextPage() {
20471cb0ef41Sopenharmony_ci        return this.version.getNextPage(this);
20481cb0ef41Sopenharmony_ci      }
20491cb0ef41Sopenharmony_ci
20501cb0ef41Sopenharmony_ci      static fromJSON(version, name, data) {
20511cb0ef41Sopenharmony_ci        let page = new PageVersion(version, pages.get(name));
20521cb0ef41Sopenharmony_ci        // Distinguish between the legacy format which just uses Arrays,
20531cb0ef41Sopenharmony_ci        // or the new object style.
20541cb0ef41Sopenharmony_ci        if (Array.isArray(data)) {
20551cb0ef41Sopenharmony_ci          for (let i = 0; i < data.length; i++) {
20561cb0ef41Sopenharmony_ci            page.add(Entry.fromLegacyJSON(i, data[data.length - i - 1]));
20571cb0ef41Sopenharmony_ci          }
20581cb0ef41Sopenharmony_ci        } else {
20591cb0ef41Sopenharmony_ci          let position = 0;
20601cb0ef41Sopenharmony_ci          for (let metric_name in data) {
20611cb0ef41Sopenharmony_ci            page.add(Entry.fromJSON(position, metric_name, data[metric_name]));
20621cb0ef41Sopenharmony_ci            position++;
20631cb0ef41Sopenharmony_ci          }
20641cb0ef41Sopenharmony_ci        }
20651cb0ef41Sopenharmony_ci        page.sort();
20661cb0ef41Sopenharmony_ci        return page
20671cb0ef41Sopenharmony_ci      }
20681cb0ef41Sopenharmony_ci
20691cb0ef41Sopenharmony_ci      static fromTXT(version, defaultName, txt) {
20701cb0ef41Sopenharmony_ci        const kPageNameIdentifier = "== Page:";
20711cb0ef41Sopenharmony_ci        const kCommentStart = "=="
20721cb0ef41Sopenharmony_ci        const lines = txt.split('\n');
20731cb0ef41Sopenharmony_ci        const split = / +/g
20741cb0ef41Sopenharmony_ci        const result = [];
20751cb0ef41Sopenharmony_ci        let pageVersion = undefined;
20761cb0ef41Sopenharmony_ci        for (let i = 0; i < lines.length; i++) {
20771cb0ef41Sopenharmony_ci          const line = lines[i];
20781cb0ef41Sopenharmony_ci          // Skip header separators
20791cb0ef41Sopenharmony_ci          if (line.startsWith(kCommentStart)) {
20801cb0ef41Sopenharmony_ci            // Check for page names
20811cb0ef41Sopenharmony_ci            if (line.startsWith(kPageNameIdentifier)) {
20821cb0ef41Sopenharmony_ci              const name = line.split(kPageNameIdentifier)[1];
20831cb0ef41Sopenharmony_ci              pageVersion = new PageVersion(version, pages.get(name));
20841cb0ef41Sopenharmony_ci              result.push(pageVersion);
20851cb0ef41Sopenharmony_ci            }
20861cb0ef41Sopenharmony_ci          }
20871cb0ef41Sopenharmony_ci          // Skip header lines.
20881cb0ef41Sopenharmony_ci          if (lines[i + 1]?.startsWith(kCommentStart)) continue;
20891cb0ef41Sopenharmony_ci          const split_line = line.trim().split(split)
20901cb0ef41Sopenharmony_ci          if (split_line.length != 5) continue;
20911cb0ef41Sopenharmony_ci          if (pageVersion === undefined) {
20921cb0ef41Sopenharmony_ci            pageVersion = new PageVersion(version, pages.get(defaultName));
20931cb0ef41Sopenharmony_ci            result.push(pageVersion);
20941cb0ef41Sopenharmony_ci          }
20951cb0ef41Sopenharmony_ci          const position = i - 2;
20961cb0ef41Sopenharmony_ci          pageVersion.add(Entry.fromTXT(position, split_line));
20971cb0ef41Sopenharmony_ci        }
20981cb0ef41Sopenharmony_ci        return result;
20991cb0ef41Sopenharmony_ci      }
21001cb0ef41Sopenharmony_ci    }
21011cb0ef41Sopenharmony_ci
21021cb0ef41Sopenharmony_ci
21031cb0ef41Sopenharmony_ci    class Entry {
21041cb0ef41Sopenharmony_ci      constructor(position, name, time, timeVariance, timeVariancePercent,
21051cb0ef41Sopenharmony_ci        count, countVariance, countVariancePercent) {
21061cb0ef41Sopenharmony_ci        this.position = position;
21071cb0ef41Sopenharmony_ci        this.name = name;
21081cb0ef41Sopenharmony_ci        this._time = time;
21091cb0ef41Sopenharmony_ci        this._timeVariance = timeVariance;
21101cb0ef41Sopenharmony_ci        this._timeVariancePercent =
21111cb0ef41Sopenharmony_ci            this._variancePercent(time, timeVariance, timeVariancePercent);
21121cb0ef41Sopenharmony_ci        this._count = count;
21131cb0ef41Sopenharmony_ci        this.countVariance = countVariance;
21141cb0ef41Sopenharmony_ci        this.countVariancePercent =
21151cb0ef41Sopenharmony_ci            this._variancePercent(count, countVariance, countVariancePercent);
21161cb0ef41Sopenharmony_ci        this.page = undefined;
21171cb0ef41Sopenharmony_ci        this.parent = undefined;
21181cb0ef41Sopenharmony_ci        this.isTotal = false;
21191cb0ef41Sopenharmony_ci      }
21201cb0ef41Sopenharmony_ci      _variancePercent(value, valueVariance, valueVariancePercent) {
21211cb0ef41Sopenharmony_ci        if (valueVariancePercent) return valueVariancePercent;
21221cb0ef41Sopenharmony_ci        if (!valueVariance) return 0;
21231cb0ef41Sopenharmony_ci        return valueVariance / value * 100;
21241cb0ef41Sopenharmony_ci      }
21251cb0ef41Sopenharmony_ci
21261cb0ef41Sopenharmony_ci      add(entry) {
21271cb0ef41Sopenharmony_ci        if (this.name !== entry.name) {
21281cb0ef41Sopenharmony_ci          console.error("Should not combine entries with different names");
21291cb0ef41Sopenharmony_ci          return;
21301cb0ef41Sopenharmony_ci        }
21311cb0ef41Sopenharmony_ci        this._time += entry._time;
21321cb0ef41Sopenharmony_ci        this._count += entry._count;
21331cb0ef41Sopenharmony_ci      }
21341cb0ef41Sopenharmony_ci      urlParams() {
21351cb0ef41Sopenharmony_ci        let params = this.page.urlParams();
21361cb0ef41Sopenharmony_ci        params.entry = this.name;
21371cb0ef41Sopenharmony_ci        return params;
21381cb0ef41Sopenharmony_ci      }
21391cb0ef41Sopenharmony_ci      getCompareWithBaseline(value, property) {
21401cb0ef41Sopenharmony_ci        if (baselineVersion == undefined) return value;
21411cb0ef41Sopenharmony_ci        let baselineEntry = baselineVersion.getEntry(this);
21421cb0ef41Sopenharmony_ci        if (!baselineEntry) return value;
21431cb0ef41Sopenharmony_ci        if (baselineVersion === this.page.version) return value;
21441cb0ef41Sopenharmony_ci        return value - baselineEntry[property];
21451cb0ef41Sopenharmony_ci      }
21461cb0ef41Sopenharmony_ci      cssClass() {
21471cb0ef41Sopenharmony_ci        return ''
21481cb0ef41Sopenharmony_ci      }
21491cb0ef41Sopenharmony_ci      get time() {
21501cb0ef41Sopenharmony_ci        return this.getCompareWithBaseline(this._time, '_time');
21511cb0ef41Sopenharmony_ci      }
21521cb0ef41Sopenharmony_ci      get count() {
21531cb0ef41Sopenharmony_ci        return this.getCompareWithBaseline(this._count, '_count');
21541cb0ef41Sopenharmony_ci      }
21551cb0ef41Sopenharmony_ci      get timePercent() {
21561cb0ef41Sopenharmony_ci        let value = this._time / this.page.total._time * 100;
21571cb0ef41Sopenharmony_ci        if (baselineVersion == undefined) return value;
21581cb0ef41Sopenharmony_ci        let baselineEntry = baselineVersion.getEntry(this);
21591cb0ef41Sopenharmony_ci        if (!baselineEntry) return value;
21601cb0ef41Sopenharmony_ci        if (baselineVersion === this.page.version) return value;
21611cb0ef41Sopenharmony_ci        return (this._time - baselineEntry._time) / this.page.total._time *
21621cb0ef41Sopenharmony_ci          100;
21631cb0ef41Sopenharmony_ci      }
21641cb0ef41Sopenharmony_ci      get timePercentPerEntry() {
21651cb0ef41Sopenharmony_ci        let value = this._time / this.page.total._time * 100;
21661cb0ef41Sopenharmony_ci        if (baselineVersion == undefined) return value;
21671cb0ef41Sopenharmony_ci        let baselineEntry = baselineVersion.getEntry(this);
21681cb0ef41Sopenharmony_ci        if (!baselineEntry) return value;
21691cb0ef41Sopenharmony_ci        if (baselineVersion === this.page.version) return value;
21701cb0ef41Sopenharmony_ci        return (this._time / baselineEntry._time - 1) * 100;
21711cb0ef41Sopenharmony_ci      }
21721cb0ef41Sopenharmony_ci      get timePercentVariancePercent() {
21731cb0ef41Sopenharmony_ci        // Get the absolute values for the percentages
21741cb0ef41Sopenharmony_ci        return this.timeVariance / this.page.total._time * 100;
21751cb0ef41Sopenharmony_ci      }
21761cb0ef41Sopenharmony_ci      getTimeImpact(showDiff) {
21771cb0ef41Sopenharmony_ci        return this.page.version.getTotalTime(this.name, showDiff);
21781cb0ef41Sopenharmony_ci      }
21791cb0ef41Sopenharmony_ci      getTimeImpactVariancePercent(showDiff) {
21801cb0ef41Sopenharmony_ci        return this.page.version.getTotalTimeVariancePercent(this.name, showDiff);
21811cb0ef41Sopenharmony_ci      }
21821cb0ef41Sopenharmony_ci      getTimePercentImpact(showDiff) {
21831cb0ef41Sopenharmony_ci        return this.page.version.getTotalTimePercent(this.name, showDiff);
21841cb0ef41Sopenharmony_ci      }
21851cb0ef41Sopenharmony_ci      getCountImpact(showDiff) {
21861cb0ef41Sopenharmony_ci        return this.page.version.getTotalCount(this.name, showDiff);
21871cb0ef41Sopenharmony_ci      }
21881cb0ef41Sopenharmony_ci      getAverageTimeImpact(showDiff) {
21891cb0ef41Sopenharmony_ci        return this.page.version.getAverageTimeImpact(this.name, showDiff);
21901cb0ef41Sopenharmony_ci      }
21911cb0ef41Sopenharmony_ci      getPagesByPercentImpact() {
21921cb0ef41Sopenharmony_ci        return this.page.version.getPagesByPercentImpact(this.name);
21931cb0ef41Sopenharmony_ci      }
21941cb0ef41Sopenharmony_ci      get isGroup() {
21951cb0ef41Sopenharmony_ci        return false;
21961cb0ef41Sopenharmony_ci      }
21971cb0ef41Sopenharmony_ci      get timeVariance() {
21981cb0ef41Sopenharmony_ci        return this._timeVariance;
21991cb0ef41Sopenharmony_ci      }
22001cb0ef41Sopenharmony_ci      get timeVariancePercent() {
22011cb0ef41Sopenharmony_ci        return this._timeVariancePercent;
22021cb0ef41Sopenharmony_ci      }
22031cb0ef41Sopenharmony_ci
22041cb0ef41Sopenharmony_ci      static fromLegacyJSON(position, data) {
22051cb0ef41Sopenharmony_ci        return new Entry(position, ...data);
22061cb0ef41Sopenharmony_ci      }
22071cb0ef41Sopenharmony_ci
22081cb0ef41Sopenharmony_ci      static fromJSON(position, name, data) {
22091cb0ef41Sopenharmony_ci        let time = data.duration;
22101cb0ef41Sopenharmony_ci        let count = data.count;
22111cb0ef41Sopenharmony_ci        return new Entry(position, name, time.average, time.stddev, 0,
22121cb0ef41Sopenharmony_ci            count.average, count.stddev, 0);
22131cb0ef41Sopenharmony_ci      }
22141cb0ef41Sopenharmony_ci
22151cb0ef41Sopenharmony_ci      static fromTXT(position, splitLine) {
22161cb0ef41Sopenharmony_ci        const name = splitLine[0];
22171cb0ef41Sopenharmony_ci        let time = splitLine[1];
22181cb0ef41Sopenharmony_ci        const msIndex = time.indexOf('m');
22191cb0ef41Sopenharmony_ci        if (msIndex > 0) time = time.substring(0, msIndex);
22201cb0ef41Sopenharmony_ci        const timePercent = splitLine[2];
22211cb0ef41Sopenharmony_ci        const count = splitLine[3];
22221cb0ef41Sopenharmony_ci        const countPercent = splitLine[4];
22231cb0ef41Sopenharmony_ci        const timeDeviation = 0;
22241cb0ef41Sopenharmony_ci        const countDeviation = 0;
22251cb0ef41Sopenharmony_ci        const timeDeviationPercent = 0;
22261cb0ef41Sopenharmony_ci        const countDeviationPercent = 0
22271cb0ef41Sopenharmony_ci        return new Entry(position, name,
22281cb0ef41Sopenharmony_ci          Number.parseFloat(time), timeDeviation, timeDeviationPercent,
22291cb0ef41Sopenharmony_ci          Number.parseInt(count), countDeviation, countDeviationPercent)
22301cb0ef41Sopenharmony_ci      }
22311cb0ef41Sopenharmony_ci    }
22321cb0ef41Sopenharmony_ci
22331cb0ef41Sopenharmony_ci    class Group {
22341cb0ef41Sopenharmony_ci      constructor(name, regexp, color, enabled = true, addsToTotal = true) {
22351cb0ef41Sopenharmony_ci        this.name = name;
22361cb0ef41Sopenharmony_ci        this.regexp = regexp;
22371cb0ef41Sopenharmony_ci        this.color = color;
22381cb0ef41Sopenharmony_ci        this.enabled = enabled;
22391cb0ef41Sopenharmony_ci        this.addsToTotal = addsToTotal;
22401cb0ef41Sopenharmony_ci      }
22411cb0ef41Sopenharmony_ci      entry() {
22421cb0ef41Sopenharmony_ci        return new GroupedEntry(this);
22431cb0ef41Sopenharmony_ci      }
22441cb0ef41Sopenharmony_ci    }
22451cb0ef41Sopenharmony_ci    Group.groups = new Map();
22461cb0ef41Sopenharmony_ci    Group.add = function (name, group) {
22471cb0ef41Sopenharmony_ci      this.groups.set(name, group);
22481cb0ef41Sopenharmony_ci      return group;
22491cb0ef41Sopenharmony_ci    }
22501cb0ef41Sopenharmony_ci    Group.add('total', new Group('Total', /.*Total.*/, '#BBB', true, false));
22511cb0ef41Sopenharmony_ci    Group.add('ic', new Group('IC', /(.*IC_.*)|IC/, "#3366CC"));
22521cb0ef41Sopenharmony_ci    Group.add('optimize-background', new Group('Optimize-Background',
22531cb0ef41Sopenharmony_ci      /.*Optimize(d?-?)(Background|Concurrent).*/, "#702000"));
22541cb0ef41Sopenharmony_ci    Group.add('optimize', new Group('Optimize',
22551cb0ef41Sopenharmony_ci      /(StackGuard|Optimize|Deoptimize|Recompile).*/, "#DC3912"));
22561cb0ef41Sopenharmony_ci    Group.add('compile-background', new Group('Compile-Background',
22571cb0ef41Sopenharmony_ci      /(.*Compile-?Background.*)/, "#b08000"));
22581cb0ef41Sopenharmony_ci    Group.add('compile', new Group('Compile',
22591cb0ef41Sopenharmony_ci      /(^Compile.*)|(.*_Compile.*)/, "#FFAA00"));
22601cb0ef41Sopenharmony_ci    Group.add('parse-background',
22611cb0ef41Sopenharmony_ci      new Group('Parse-Background', /.*Parse-?Background.*/, "#c05000"));
22621cb0ef41Sopenharmony_ci    Group.add('parse', new Group('Parse', /.*Parse.*/, "#FF6600"));
22631cb0ef41Sopenharmony_ci    Group.add('callback',
22641cb0ef41Sopenharmony_ci      new Group('Blink C++', /.*(Callback)|(Blink C\+\+).*/, "#109618"));
22651cb0ef41Sopenharmony_ci    Group.add('api', new Group('API', /.*API.*/, "#990099"));
22661cb0ef41Sopenharmony_ci    Group.add('gc-custom', new Group('GC-Custom', /GC_Custom_.*/, "#0099C6"));
22671cb0ef41Sopenharmony_ci    Group.add('gc-background',
22681cb0ef41Sopenharmony_ci      new Group(
22691cb0ef41Sopenharmony_ci        'GC-Background', /.*GC.*(BACKGROUND|Background).*/, "#00597c"));
22701cb0ef41Sopenharmony_ci    Group.add('gc',
22711cb0ef41Sopenharmony_ci      new Group('GC', /GC_.*|AllocateInTargetSpace|GC/, "#00799c"));
22721cb0ef41Sopenharmony_ci    Group.add('javascript',
22731cb0ef41Sopenharmony_ci      new Group('JavaScript', /JS_Execution|JavaScript/, "#DD4477"));
22741cb0ef41Sopenharmony_ci    Group.add('websnapshot', new Group('WebSnapshot', /.*Web.*/, "#E8E11C"));
22751cb0ef41Sopenharmony_ci    Group.add('runtime', new Group('V8 C++', /.*/, "#88BB00"));
22761cb0ef41Sopenharmony_ci    Group.add('blink',
22771cb0ef41Sopenharmony_ci      new Group('Blink RCS', /.*Blink_.*/, "#006600", false, false));
22781cb0ef41Sopenharmony_ci    Group.add('unclassified', new Group('Unclassified', /.*/, "#000", false));
22791cb0ef41Sopenharmony_ci
22801cb0ef41Sopenharmony_ci    class GroupedEntry extends Entry {
22811cb0ef41Sopenharmony_ci      constructor(group) {
22821cb0ef41Sopenharmony_ci        super(0, GroupedEntry.prefix + group.name, 0, 0, 0, 0, 0, 0);
22831cb0ef41Sopenharmony_ci        this.group = group;
22841cb0ef41Sopenharmony_ci        this.entries = [];
22851cb0ef41Sopenharmony_ci        this.missingEntries = null;
22861cb0ef41Sopenharmony_ci        this.addsToTotal = group.addsToTotal;
22871cb0ef41Sopenharmony_ci      }
22881cb0ef41Sopenharmony_ci      get regexp() {
22891cb0ef41Sopenharmony_ci        return this.group.regexp;
22901cb0ef41Sopenharmony_ci      }
22911cb0ef41Sopenharmony_ci      get color() {
22921cb0ef41Sopenharmony_ci        return this.group.color;
22931cb0ef41Sopenharmony_ci      }
22941cb0ef41Sopenharmony_ci      get enabled() {
22951cb0ef41Sopenharmony_ci        return this.group.enabled;
22961cb0ef41Sopenharmony_ci      }
22971cb0ef41Sopenharmony_ci      add(entry) {
22981cb0ef41Sopenharmony_ci        if (!this.addTimeAndCount(entry)) return;
22991cb0ef41Sopenharmony_ci        // TODO: sum up variance
23001cb0ef41Sopenharmony_ci        this.entries.push(entry);
23011cb0ef41Sopenharmony_ci        entry.parent = this;
23021cb0ef41Sopenharmony_ci        return true;
23031cb0ef41Sopenharmony_ci      }
23041cb0ef41Sopenharmony_ci      addTimeAndCount(entry) {
23051cb0ef41Sopenharmony_ci        if (!this.regexp.test(entry.name)) return false;
23061cb0ef41Sopenharmony_ci        this._time += entry.time;
23071cb0ef41Sopenharmony_ci        this._count += entry.count;
23081cb0ef41Sopenharmony_ci        return true;
23091cb0ef41Sopenharmony_ci      }
23101cb0ef41Sopenharmony_ci      _initializeMissingEntries() {
23111cb0ef41Sopenharmony_ci        let dummyEntryNames = new Set();
23121cb0ef41Sopenharmony_ci        versions.forEach((version) => {
23131cb0ef41Sopenharmony_ci          let page = version.getOrCreate(this.page.name);
23141cb0ef41Sopenharmony_ci          let groupEntry = page.get(this.name);
23151cb0ef41Sopenharmony_ci          if (groupEntry != this) {
23161cb0ef41Sopenharmony_ci            for (let entry of groupEntry.entries) {
23171cb0ef41Sopenharmony_ci              if (this.page.get(entry.name) == undefined) {
23181cb0ef41Sopenharmony_ci                dummyEntryNames.add(entry.name);
23191cb0ef41Sopenharmony_ci              }
23201cb0ef41Sopenharmony_ci            }
23211cb0ef41Sopenharmony_ci          }
23221cb0ef41Sopenharmony_ci        });
23231cb0ef41Sopenharmony_ci        this.missingEntries = [];
23241cb0ef41Sopenharmony_ci        for (let name of dummyEntryNames) {
23251cb0ef41Sopenharmony_ci          let tmpEntry = new Entry(0, name, 0, 0, 0, 0, 0, 0);
23261cb0ef41Sopenharmony_ci          tmpEntry.page = this.page;
23271cb0ef41Sopenharmony_ci          this.missingEntries.push(tmpEntry);
23281cb0ef41Sopenharmony_ci        };
23291cb0ef41Sopenharmony_ci      }
23301cb0ef41Sopenharmony_ci      forEach(fun) {
23311cb0ef41Sopenharmony_ci        // Show also all entries which are in at least one version.
23321cb0ef41Sopenharmony_ci        // Concatenate our real entries.
23331cb0ef41Sopenharmony_ci        if (this.missingEntries == null) {
23341cb0ef41Sopenharmony_ci          this._initializeMissingEntries();
23351cb0ef41Sopenharmony_ci        }
23361cb0ef41Sopenharmony_ci        let tmpEntries = this.missingEntries.concat(this.entries);
23371cb0ef41Sopenharmony_ci
23381cb0ef41Sopenharmony_ci        // The compared entries are sorted by absolute impact.
23391cb0ef41Sopenharmony_ci        tmpEntries.sort((a, b) => {
23401cb0ef41Sopenharmony_ci          return b.time - a.time
23411cb0ef41Sopenharmony_ci        });
23421cb0ef41Sopenharmony_ci        tmpEntries.forEach(fun);
23431cb0ef41Sopenharmony_ci      }
23441cb0ef41Sopenharmony_ci      sort() {
23451cb0ef41Sopenharmony_ci        this.entries.sort((a, b) => {
23461cb0ef41Sopenharmony_ci          return b.time - a.time;
23471cb0ef41Sopenharmony_ci        });
23481cb0ef41Sopenharmony_ci      }
23491cb0ef41Sopenharmony_ci      cssClass() {
23501cb0ef41Sopenharmony_ci        if (this.page.total == this) return 'total';
23511cb0ef41Sopenharmony_ci        return '';
23521cb0ef41Sopenharmony_ci      }
23531cb0ef41Sopenharmony_ci      get isGroup() {
23541cb0ef41Sopenharmony_ci        return true
23551cb0ef41Sopenharmony_ci      }
23561cb0ef41Sopenharmony_ci      getVarianceForProperty(property) {
23571cb0ef41Sopenharmony_ci        let sum = 0;
23581cb0ef41Sopenharmony_ci        const key = property + 'Variance';
23591cb0ef41Sopenharmony_ci        this.entries.forEach((entry) => {
23601cb0ef41Sopenharmony_ci          const value = entry[key];
23611cb0ef41Sopenharmony_ci          sum += value * value;
23621cb0ef41Sopenharmony_ci        });
23631cb0ef41Sopenharmony_ci        return Math.sqrt(sum);
23641cb0ef41Sopenharmony_ci      }
23651cb0ef41Sopenharmony_ci      get timeVariancePercent() {
23661cb0ef41Sopenharmony_ci        if (this._time == 0) return 0;
23671cb0ef41Sopenharmony_ci        return this.getVarianceForProperty('time') / this._time * 100
23681cb0ef41Sopenharmony_ci      }
23691cb0ef41Sopenharmony_ci      get timeVariance() {
23701cb0ef41Sopenharmony_ci        return this.getVarianceForProperty('time')
23711cb0ef41Sopenharmony_ci      }
23721cb0ef41Sopenharmony_ci    }
23731cb0ef41Sopenharmony_ci    GroupedEntry.prefix = 'Group-';
23741cb0ef41Sopenharmony_ci
23751cb0ef41Sopenharmony_ci    class UnclassifiedEntry extends GroupedEntry {
23761cb0ef41Sopenharmony_ci      constructor(page) {
23771cb0ef41Sopenharmony_ci        super(Group.groups.get('unclassified'));
23781cb0ef41Sopenharmony_ci        this.page = page;
23791cb0ef41Sopenharmony_ci        this._time = undefined;
23801cb0ef41Sopenharmony_ci        this._count = undefined;
23811cb0ef41Sopenharmony_ci      }
23821cb0ef41Sopenharmony_ci      add(entry) {
23831cb0ef41Sopenharmony_ci        console.log("Adding unclassified:", entry);
23841cb0ef41Sopenharmony_ci        this.entries.push(entry);
23851cb0ef41Sopenharmony_ci        entry.parent = this;
23861cb0ef41Sopenharmony_ci        return true;
23871cb0ef41Sopenharmony_ci      }
23881cb0ef41Sopenharmony_ci      forEachPageGroup(fun) {
23891cb0ef41Sopenharmony_ci        this.page.forEachGroup((group) => {
23901cb0ef41Sopenharmony_ci          if (group == this) return;
23911cb0ef41Sopenharmony_ci          if (group == this.page.total) return;
23921cb0ef41Sopenharmony_ci          fun(group);
23931cb0ef41Sopenharmony_ci        });
23941cb0ef41Sopenharmony_ci      }
23951cb0ef41Sopenharmony_ci      get time() {
23961cb0ef41Sopenharmony_ci        if (this._time === undefined) {
23971cb0ef41Sopenharmony_ci          this._time = this.page.total._time;
23981cb0ef41Sopenharmony_ci          this.forEachPageGroup((group) => {
23991cb0ef41Sopenharmony_ci            if (group.addsToTotal) this._time -= group._time;
24001cb0ef41Sopenharmony_ci          });
24011cb0ef41Sopenharmony_ci        }
24021cb0ef41Sopenharmony_ci        return this.getCompareWithBaseline(this._time, '_time');
24031cb0ef41Sopenharmony_ci      }
24041cb0ef41Sopenharmony_ci      get count() {
24051cb0ef41Sopenharmony_ci        if (this._count === undefined) {
24061cb0ef41Sopenharmony_ci          this._count = this.page.total._count;
24071cb0ef41Sopenharmony_ci          this.forEachPageGroup((group) => {
24081cb0ef41Sopenharmony_ci            this._count -= group._count;
24091cb0ef41Sopenharmony_ci          });
24101cb0ef41Sopenharmony_ci        }
24111cb0ef41Sopenharmony_ci        return this.getCompareWithBaseline(this._count, '_count');
24121cb0ef41Sopenharmony_ci      }
24131cb0ef41Sopenharmony_ci    }
24141cb0ef41Sopenharmony_ci  </script>
24151cb0ef41Sopenharmony_ci</head>
24161cb0ef41Sopenharmony_ci
24171cb0ef41Sopenharmony_ci<body id="body" onmousemove="handleUpdatePopover(event)" onload="handleBodyLoad()" class="noDiff">
24181cb0ef41Sopenharmony_ci  <h1>Runtime Stats Komparator</h1>
24191cb0ef41Sopenharmony_ci
24201cb0ef41Sopenharmony_ci  <section id="inputs" class="panel alwaysVisible">
24211cb0ef41Sopenharmony_ci    <input type="checkbox" id="inputsCheckbox" class="panelCloserInput">
24221cb0ef41Sopenharmony_ci    <label class="panelCloserLabel" for="inputsCheckbox">▼</label>
24231cb0ef41Sopenharmony_ci    <h2>Input/Output</h2>
24241cb0ef41Sopenharmony_ci    <div class="panelBody">
24251cb0ef41Sopenharmony_ci      <form name="fileForm" class="inline">
24261cb0ef41Sopenharmony_ci        <p class="inline">
24271cb0ef41Sopenharmony_ci          <label for="uploadInput">Load Files:</label>
24281cb0ef41Sopenharmony_ci          <input id="uploadInput" type="file" name="files" onchange="handleLoadFiles();" multiple
24291cb0ef41Sopenharmony_ci            accept=".json,.txt,.csv,.output">
24301cb0ef41Sopenharmony_ci        </p>
24311cb0ef41Sopenharmony_ci        <p class="inline">
24321cb0ef41Sopenharmony_ci          <label for="appendInput">Append Files:</label>
24331cb0ef41Sopenharmony_ci          <input id="appendInput" type="file" name="files" onchange="handleAppendFiles();" multiple
24341cb0ef41Sopenharmony_ci            accept=".json,.txt,.csv,.output">
24351cb0ef41Sopenharmony_ci        </p>
24361cb0ef41Sopenharmony_ci      </form>
24371cb0ef41Sopenharmony_ci      <p class="inline">
24381cb0ef41Sopenharmony_ci        <button onclick="handleCopyToClipboard()">Copy Table to Clipboard</button>
24391cb0ef41Sopenharmony_ci      </p>
24401cb0ef41Sopenharmony_ci    </div>
24411cb0ef41Sopenharmony_ci  </section>
24421cb0ef41Sopenharmony_ci
24431cb0ef41Sopenharmony_ci  <section class="panel">
24441cb0ef41Sopenharmony_ci    <h2>Baseline Selector</h2>
24451cb0ef41Sopenharmony_ci    <div class="panel-body">
24461cb0ef41Sopenharmony_ci      Compare against baseline:&nbsp;<select id="baseline" onchange="handleSelectBaseline(this, event)"></select><br />
24471cb0ef41Sopenharmony_ci      <span style="color: #060">Green</span> a selected version performs
24481cb0ef41Sopenharmony_ci      better than the baseline.
24491cb0ef41Sopenharmony_ci    </div>
24501cb0ef41Sopenharmony_ci  </section>
24511cb0ef41Sopenharmony_ci
24521cb0ef41Sopenharmony_ci  <section class="panel-group">
24531cb0ef41Sopenharmony_ci    <div id="versionSelector" class="panel">
24541cb0ef41Sopenharmony_ci      <input type="checkbox" checked id="versionSelectorCheckbox" class="panelCloserInput">
24551cb0ef41Sopenharmony_ci      <label class="panelCloserLabel" for="versionSelectorCheckbox">▼</label>
24561cb0ef41Sopenharmony_ci      <h2>Selected Versions</h2>
24571cb0ef41Sopenharmony_ci      <div class="panelBody">
24581cb0ef41Sopenharmony_ci        <ul></ul>
24591cb0ef41Sopenharmony_ci      </div>
24601cb0ef41Sopenharmony_ci    </div>
24611cb0ef41Sopenharmony_ci
24621cb0ef41Sopenharmony_ci    <div id="pageSelector" class="panel">
24631cb0ef41Sopenharmony_ci      <input type="checkbox" checked id="pageSelectorCheckbox" class="panelCloserInput">
24641cb0ef41Sopenharmony_ci      <label class="panelCloserLabel" for="pageSelectorCheckbox">▼</label>
24651cb0ef41Sopenharmony_ci      <h2>Selected Pages</h2>
24661cb0ef41Sopenharmony_ci      <div class="panelBody">
24671cb0ef41Sopenharmony_ci        <ul></ul>
24681cb0ef41Sopenharmony_ci      </div>
24691cb0ef41Sopenharmony_ci    </div>
24701cb0ef41Sopenharmony_ci
24711cb0ef41Sopenharmony_ci    <div id="groupSelector" class="panel">
24721cb0ef41Sopenharmony_ci      <input type="checkbox" checked id="groupSelectorCheckbox" class="panelCloserInput">
24731cb0ef41Sopenharmony_ci      <label class="panelCloserLabel" for="groupSelectorCheckbox">▼</label>
24741cb0ef41Sopenharmony_ci      <h2>Selected RCS Groups</h2>
24751cb0ef41Sopenharmony_ci      <div class="panelBody">
24761cb0ef41Sopenharmony_ci        <ul></ul>
24771cb0ef41Sopenharmony_ci      </div>
24781cb0ef41Sopenharmony_ci    </div>
24791cb0ef41Sopenharmony_ci  </section>
24801cb0ef41Sopenharmony_ci
24811cb0ef41Sopenharmony_ci  <section id="view" class="panel">
24821cb0ef41Sopenharmony_ci    <input type="checkbox" id="tableViewCheckbox" class="panelCloserInput">
24831cb0ef41Sopenharmony_ci    <label class="panelCloserLabel" for="tableViewCheckbox">▼</label>
24841cb0ef41Sopenharmony_ci    <h2>RCS Table</h2>
24851cb0ef41Sopenharmony_ci    <div class="panelBody"></div>
24861cb0ef41Sopenharmony_ci  </section>
24871cb0ef41Sopenharmony_ci
24881cb0ef41Sopenharmony_ci  <section class="panel-group">
24891cb0ef41Sopenharmony_ci    <div id="versionDetails" class="panel">
24901cb0ef41Sopenharmony_ci      <input type="checkbox" checked id="versionDetailCheckbox" class="panelCloserInput">
24911cb0ef41Sopenharmony_ci      <label class="panelCloserLabel" for="versionDetailCheckbox">▼</label>
24921cb0ef41Sopenharmony_ci      <h2><span>Compare Page Versions</span></h2>
24931cb0ef41Sopenharmony_ci      <div class="conten panelBody">
24941cb0ef41Sopenharmony_ci        <table class="versionDetailTable" onclick="handleSelectDetailRow(this, event);">
24951cb0ef41Sopenharmony_ci          <thead>
24961cb0ef41Sopenharmony_ci            <tr>
24971cb0ef41Sopenharmony_ci              <th class="version">Version&nbsp;</th>
24981cb0ef41Sopenharmony_ci              <th class="position">Pos.&nbsp;</th>
24991cb0ef41Sopenharmony_ci              <th class="value time">Time▴&nbsp;</th>
25001cb0ef41Sopenharmony_ci              <th class="value time">Percent&nbsp;</th>
25011cb0ef41Sopenharmony_ci              <th class="value count">Count&nbsp;</th>
25021cb0ef41Sopenharmony_ci            </tr>
25031cb0ef41Sopenharmony_ci          </thead>
25041cb0ef41Sopenharmony_ci          <tbody></tbody>
25051cb0ef41Sopenharmony_ci        </table>
25061cb0ef41Sopenharmony_ci      </div>
25071cb0ef41Sopenharmony_ci    </div>
25081cb0ef41Sopenharmony_ci
25091cb0ef41Sopenharmony_ci    <div id="pageDetail" class="panel">
25101cb0ef41Sopenharmony_ci      <input type="checkbox" checked id="pageDetailCheckbox" class="panelCloserInput">
25111cb0ef41Sopenharmony_ci      <label class="panelCloserLabel" for="pageDetailCheckbox">▼</label>
25121cb0ef41Sopenharmony_ci      <h2>Page Comparison for <span></span></h2>
25131cb0ef41Sopenharmony_ci      <div class="panelBody">
25141cb0ef41Sopenharmony_ci        <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);">
25151cb0ef41Sopenharmony_ci          <thead>
25161cb0ef41Sopenharmony_ci            <tr>
25171cb0ef41Sopenharmony_ci              <th class="page">Page&nbsp;</th>
25181cb0ef41Sopenharmony_ci              <th class="value time">Time&nbsp;</th>
25191cb0ef41Sopenharmony_ci              <th class="value time">Percent▾&nbsp;</th>
25201cb0ef41Sopenharmony_ci              <th class="value time hideNoDiff">%/Entry&nbsp;</th>
25211cb0ef41Sopenharmony_ci              <th class="value count">Count&nbsp;</th>
25221cb0ef41Sopenharmony_ci            </tr>
25231cb0ef41Sopenharmony_ci          </thead>
25241cb0ef41Sopenharmony_ci          <tfoot>
25251cb0ef41Sopenharmony_ci            <tr>
25261cb0ef41Sopenharmony_ci              <td class="page">Total:</td>
25271cb0ef41Sopenharmony_ci              <td class="value time"></td>
25281cb0ef41Sopenharmony_ci              <td class="value time"></td>
25291cb0ef41Sopenharmony_ci              <td class="value time hideNoDiff"></td>
25301cb0ef41Sopenharmony_ci              <td class="value count"></td>
25311cb0ef41Sopenharmony_ci            </tr>
25321cb0ef41Sopenharmony_ci          </tfoot>
25331cb0ef41Sopenharmony_ci          <tbody></tbody>
25341cb0ef41Sopenharmony_ci        </table>
25351cb0ef41Sopenharmony_ci      </div>
25361cb0ef41Sopenharmony_ci    </div>
25371cb0ef41Sopenharmony_ci
25381cb0ef41Sopenharmony_ci    <div id="impactView" class="panel">
25391cb0ef41Sopenharmony_ci      <input type="checkbox" checked id="impactViewCheckbox" class="panelCloserInput">
25401cb0ef41Sopenharmony_ci      <label class="panelCloserLabel" for="impactViewCheckbox">▼</label>
25411cb0ef41Sopenharmony_ci      <h2>Impact list for <span></span></h2>
25421cb0ef41Sopenharmony_ci      <div class="panelBody">
25431cb0ef41Sopenharmony_ci        <table class="pageDetailTable" onclick="handleSelectDetailRow(this, event);">
25441cb0ef41Sopenharmony_ci          <thead>
25451cb0ef41Sopenharmony_ci            <tr>
25461cb0ef41Sopenharmony_ci              <th class="page">Name&nbsp;</th>
25471cb0ef41Sopenharmony_ci              <th class="value time">Time&nbsp;</th>
25481cb0ef41Sopenharmony_ci              <th class="value time">Percent▾&nbsp;</th>
25491cb0ef41Sopenharmony_ci              <th class="">Top Pages</th>
25501cb0ef41Sopenharmony_ci            </tr>
25511cb0ef41Sopenharmony_ci          </thead>
25521cb0ef41Sopenharmony_ci          <tbody></tbody>
25531cb0ef41Sopenharmony_ci        </table>
25541cb0ef41Sopenharmony_ci      </div>
25551cb0ef41Sopenharmony_ci    </div>
25561cb0ef41Sopenharmony_ci  </section>
25571cb0ef41Sopenharmony_ci
25581cb0ef41Sopenharmony_ci  <section id="pageVersionGraph" class="panel">
25591cb0ef41Sopenharmony_ci    <input type="checkbox" id="pageVersionGraphCheckbox" class="panelCloserInput">
25601cb0ef41Sopenharmony_ci    <label class="panelCloserLabel" for="pageVersionGraphCheckbox">▼</label>
25611cb0ef41Sopenharmony_ci    <h2><span></span></h2>
25621cb0ef41Sopenharmony_ci    <div class="panelBody"></div>
25631cb0ef41Sopenharmony_ci  </section>
25641cb0ef41Sopenharmony_ci
25651cb0ef41Sopenharmony_ci  <section id="pageGraph" class="panel">
25661cb0ef41Sopenharmony_ci    <input type="checkbox" id="pageGraphCheckbox" class="panelCloserInput">
25671cb0ef41Sopenharmony_ci    <label class="panelCloserLabel" for="pageGraphCheckbox">▼</label>
25681cb0ef41Sopenharmony_ci    <h2><span></span></h2>
25691cb0ef41Sopenharmony_ci    <div class="panelBody"></div>
25701cb0ef41Sopenharmony_ci  </section>
25711cb0ef41Sopenharmony_ci
25721cb0ef41Sopenharmony_ci  <section id="versionGraph" class="panel">
25731cb0ef41Sopenharmony_ci    <input type="checkbox" id="versionGraphCheckbox" class="panelCloserInput">
25741cb0ef41Sopenharmony_ci    <label class="panelCloserLabel" for="versionGraphCheckbox">▼</label>
25751cb0ef41Sopenharmony_ci    <h2><span></span></h2>
25761cb0ef41Sopenharmony_ci    <div class="panelBody"></div>
25771cb0ef41Sopenharmony_ci  </section>
25781cb0ef41Sopenharmony_ci
25791cb0ef41Sopenharmony_ci  <div id="column" class="column">
25801cb0ef41Sopenharmony_ci    <div class="header">
25811cb0ef41Sopenharmony_ci      <select class="version" onchange="handleSelectVersion(this, event);"></select>
25821cb0ef41Sopenharmony_ci      <select class="pageVersion" onchange="handleSelectPage(this, event);"></select>
25831cb0ef41Sopenharmony_ci    </div>
25841cb0ef41Sopenharmony_ci    <table class="list" onclick="handleSelectRow(this, event);">
25851cb0ef41Sopenharmony_ci      <thead>
25861cb0ef41Sopenharmony_ci        <tr>
25871cb0ef41Sopenharmony_ci          <th class="position">Pos.&nbsp;</th>
25881cb0ef41Sopenharmony_ci          <th class="name">Name&nbsp;</th>
25891cb0ef41Sopenharmony_ci          <th class="value time">Time&nbsp;</th>
25901cb0ef41Sopenharmony_ci          <th class="value time">Percent&nbsp;</th>
25911cb0ef41Sopenharmony_ci          <th class="value count">Count&nbsp;</th>
25921cb0ef41Sopenharmony_ci        </tr>
25931cb0ef41Sopenharmony_ci      </thead>
25941cb0ef41Sopenharmony_ci      <tbody></tbody>
25951cb0ef41Sopenharmony_ci    </table>
25961cb0ef41Sopenharmony_ci  </div>
25971cb0ef41Sopenharmony_ci
25981cb0ef41Sopenharmony_ci  <section class="panel alwaysVisible">
25991cb0ef41Sopenharmony_ci    <h2>Instructions</h2>
26001cb0ef41Sopenharmony_ci    <div class="panelBody">
26011cb0ef41Sopenharmony_ci      <ol>
26021cb0ef41Sopenharmony_ci        <li>Build chrome.</li>
26031cb0ef41Sopenharmony_ci      </ol>
26041cb0ef41Sopenharmony_ci      <h3>Telemetry benchmark</h3>
26051cb0ef41Sopenharmony_ci      <ol>
26061cb0ef41Sopenharmony_ci        <li>Run <code>v8.browsing</code> benchmarks:
26071cb0ef41Sopenharmony_ci          <pre>$CHROMIUM_DIR/tools/perf/run_benchmark run v8.browsing_desktop \
26081cb0ef41Sopenharmony_ci            --browser=exact --browser-executable=$CHROMIUM_DIR/out/release/chrome \
26091cb0ef41Sopenharmony_ci            --story-filter='.*2020 ' \
26101cb0ef41Sopenharmony_ci            --also-run-disabled-tests
26111cb0ef41Sopenharmony_ci          </pre>
26121cb0ef41Sopenharmony_ci        </li>
26131cb0ef41Sopenharmony_ci        <li>Install <a href="https://stedolan.github.io/jq/">jq</a>.</li>
26141cb0ef41Sopenharmony_ci        <li>Convert the telemetry JSON files to callstats JSON file:
26151cb0ef41Sopenharmony_ci          <pre>
26161cb0ef41Sopenharmony_ci            $V8_DIR/tools/callstats-from-telemetry.sh $CHROMIUM_DIR/tools/perf/artifacts/run_XXXX
26171cb0ef41Sopenharmony_ci          </pre>
26181cb0ef41Sopenharmony_ci        </li>
26191cb0ef41Sopenharmony_ci        <li>Load the generated <code>out.json</code></li>
26201cb0ef41Sopenharmony_ci      </ol>
26211cb0ef41Sopenharmony_ci      <h3>Merged CSV from results.html</h3>
26221cb0ef41Sopenharmony_ci      <ol>
26231cb0ef41Sopenharmony_ci        <li>Open a results.html page for RCS-enabled benchmarks</li>
26241cb0ef41Sopenharmony_ci        <li>Select "Export merged CSV" in the toolbar</li>
26251cb0ef41Sopenharmony_ci        <li>Load the downloading .csv file normally in callstats.html</li>
26261cb0ef41Sopenharmony_ci      </ol>
26271cb0ef41Sopenharmony_ci      <h3>Aggregated raw txt output</h3>
26281cb0ef41Sopenharmony_ci      <ol>
26291cb0ef41Sopenharmony_ci        <li>Install scipy, e.g. <code>sudo aptitude install python-scipy</code>
26301cb0ef41Sopenharmony_ci        <li>Check out a known working version of webpagereply:
26311cb0ef41Sopenharmony_ci          <pre>git -C $CHROME_DIR/third_party/webpagereplay checkout 7dbd94752d1cde5536ffc623a9e10a51721eff1d</pre>
26321cb0ef41Sopenharmony_ci        </li>
26331cb0ef41Sopenharmony_ci        <li>Run <code>callstats.py</code> with a web-page-replay archive:
26341cb0ef41Sopenharmony_ci          <pre>$V8_DIR/tools/callstats.py run \
26351cb0ef41Sopenharmony_ci          --replay-bin=$CHROME_SRC/third_party/webpagereplay/replay.py \
26361cb0ef41Sopenharmony_ci          --replay-wpr=$INPUT_DIR/top25.wpr \
26371cb0ef41Sopenharmony_ci          --js-flags="" \
26381cb0ef41Sopenharmony_ci          --with-chrome=$CHROME_SRC/out/Release/chrome \
26391cb0ef41Sopenharmony_ci          --sites-file=$INPUT_DIR/top25.json</pre>
26401cb0ef41Sopenharmony_ci        </li>
26411cb0ef41Sopenharmony_ci        <li>Move results file to a subdirectory: <code>mkdir $VERSION_DIR; mv *.txt $VERSION_DIR</code></li>
26421cb0ef41Sopenharmony_ci        <li>Repeat from step 1 with a different configuration (e.g. <code>--js-flags="--nolazy"</code>).</li>
26431cb0ef41Sopenharmony_ci        <li>Create the final results file: <code>./callstats.py json $VERSION_DIR1 $VERSION_DIR2 > result.json</code>
26441cb0ef41Sopenharmony_ci        </li>
26451cb0ef41Sopenharmony_ci        <li>Use <code>results.json</code> on this site.</code>
26461cb0ef41Sopenharmony_ci      </ol>
26471cb0ef41Sopenharmony_ci    </div>
26481cb0ef41Sopenharmony_ci  </section>
26491cb0ef41Sopenharmony_ci
26501cb0ef41Sopenharmony_ci  <div id="popover">
26511cb0ef41Sopenharmony_ci    <div class="popoverArrow"></div>
26521cb0ef41Sopenharmony_ci    <table>
26531cb0ef41Sopenharmony_ci      <tr>
26541cb0ef41Sopenharmony_ci        <td class="name" colspan="6"></td>
26551cb0ef41Sopenharmony_ci      </tr>
26561cb0ef41Sopenharmony_ci      <tr>
26571cb0ef41Sopenharmony_ci        <td>Page:</td>
26581cb0ef41Sopenharmony_ci        <td class="page name" colspan="6"></td>
26591cb0ef41Sopenharmony_ci      </tr>
26601cb0ef41Sopenharmony_ci      <tr>
26611cb0ef41Sopenharmony_ci        <td>Version:</td>
26621cb0ef41Sopenharmony_ci        <td class="version name" colspan="3"></td>
26631cb0ef41Sopenharmony_ci        <td class="compare version name" colspan="3"></td>
26641cb0ef41Sopenharmony_ci      </tr>
26651cb0ef41Sopenharmony_ci      <tr>
26661cb0ef41Sopenharmony_ci        <td>Time:</td>
26671cb0ef41Sopenharmony_ci        <td class="time"></td>
26681cb0ef41Sopenharmony_ci        <td>±</td>
26691cb0ef41Sopenharmony_ci        <td class="timeVariance"></td>
26701cb0ef41Sopenharmony_ci        <td class="compare time"></td>
26711cb0ef41Sopenharmony_ci        <td class="compare"> ± </td>
26721cb0ef41Sopenharmony_ci        <td class="compare timeVariance"></td>
26731cb0ef41Sopenharmony_ci      </tr>
26741cb0ef41Sopenharmony_ci      <tr>
26751cb0ef41Sopenharmony_ci        <td>Percent:</td>
26761cb0ef41Sopenharmony_ci        <td class="percent"></td>
26771cb0ef41Sopenharmony_ci        <td>±</td>
26781cb0ef41Sopenharmony_ci        <td class="percentVariance"></td>
26791cb0ef41Sopenharmony_ci        <td class="compare percent"></td>
26801cb0ef41Sopenharmony_ci        <td class="compare"> ± </td>
26811cb0ef41Sopenharmony_ci        <td class="compare percentVariance"></td>
26821cb0ef41Sopenharmony_ci      </tr>
26831cb0ef41Sopenharmony_ci      <tr>
26841cb0ef41Sopenharmony_ci        <td>Percent per Entry:</td>
26851cb0ef41Sopenharmony_ci        <td class="percentPerEntry"></td>
26861cb0ef41Sopenharmony_ci        <td colspan=2></td>
26871cb0ef41Sopenharmony_ci        <td class="compare percentPerEntry"></td>
26881cb0ef41Sopenharmony_ci        <td colspan=2></td>
26891cb0ef41Sopenharmony_ci      </tr>
26901cb0ef41Sopenharmony_ci      <tr>
26911cb0ef41Sopenharmony_ci        <td>Count:</td>
26921cb0ef41Sopenharmony_ci        <td class="count"></td>
26931cb0ef41Sopenharmony_ci        <td>±</td>
26941cb0ef41Sopenharmony_ci        <td class="countVariance"></td>
26951cb0ef41Sopenharmony_ci        <td class="compare count"></td>
26961cb0ef41Sopenharmony_ci        <td class="compare"> ± </td>
26971cb0ef41Sopenharmony_ci        <td class="compare countVariance"></td>
26981cb0ef41Sopenharmony_ci      </tr>
26991cb0ef41Sopenharmony_ci      <tr>
27001cb0ef41Sopenharmony_ci        <td>Overall Impact:</td>
27011cb0ef41Sopenharmony_ci        <td class="timeImpact"></td>
27021cb0ef41Sopenharmony_ci        <td>±</td>
27031cb0ef41Sopenharmony_ci        <td class="timePercentImpact"></td>
27041cb0ef41Sopenharmony_ci        <td class="compare timeImpact"></td>
27051cb0ef41Sopenharmony_ci        <td class="compare"> ± </td>
27061cb0ef41Sopenharmony_ci        <td class="compare timePercentImpact"></td>
27071cb0ef41Sopenharmony_ci      </tr>
27081cb0ef41Sopenharmony_ci    </table>
27091cb0ef41Sopenharmony_ci  </div>
27101cb0ef41Sopenharmony_ci</body>
27111cb0ef41Sopenharmony_ci
27121cb0ef41Sopenharmony_ci</html>
2713