Add option to select main/release benchmarks in go/r8perf

Change-Id: I0c267fe2a15187ca0abec8495ccac9f9ca3501b1
diff --git a/tools/perf/d8.html b/tools/perf/d8.html
index 848ceea..8cced99 100644
--- a/tools/perf/d8.html
+++ b/tools/perf/d8.html
@@ -18,6 +18,12 @@
     <input type="radio" id="runtime-max" name="runtime-fn">
     <label for="runtime-max">Max</label>
   </div>
+  <div id="branch-selector">
+    <input type="radio" id="branch-main" name="branch-selector" checked>
+    <label for="branch-main">Main</label>
+    <input type="radio" id="branch-release" name="branch-selector">
+    <label for="branch-release">Release</label>
+  </div>
   <div id="benchmark-selectors"></div>
   <div>
       <canvas id="myChart"></canvas>
@@ -41,6 +47,7 @@
     import dom from "./dom.js";
     import scales from "./scales.js";
     import state from "./state.js";
+    import tooltip from "./tooltip.js";
 
     const commits = await state.importCommits("./d8_benchmark_data.json");
     state.initializeBenchmarks();
@@ -52,8 +59,7 @@
       'Warmup': { default: false }
     });
     state.initializeZoom();
-    dom.initializeBenchmarkSelectors();
-    dom.initializeChartNavigation();
+    dom.initialize();
 
     // Chart data provider.
     function getData(filteredCommits) {
@@ -255,37 +261,7 @@
             chart.update(false, true);
           },
         },
-        tooltip: {
-          callbacks: {
-            title: context => {
-              const elementInfo = context[0];
-              var commit;
-              if (elementInfo.dataset.type == 'line') {
-                commit = commits[state.zoom.left + elementInfo.dataIndex];
-              } else {
-                console.assert(elementInfo.dataset.type == 'scatter');
-                commit = commits[elementInfo.raw.x];
-              }
-              return commit.title;
-            },
-            footer: context => {
-              const elementInfo = context[0];
-              var commit;
-              if (elementInfo.dataset.type == 'line') {
-                commit = commits[state.zoom.left + elementInfo.dataIndex];
-              } else {
-                console.assert(elementInfo.dataset.type == 'scatter');
-                commit = commits[elementInfo.raw.x];
-              }
-              const dataset = chart.get().data.datasets[elementInfo.datasetIndex];
-              return `App: ${dataset.benchmark}\n`
-                  + `Author: ${commit.author}\n`
-                  + `Submitted: ${new Date(commit.submitted * 1000).toLocaleString()}\n`
-                  + `Hash: ${commit.hash}\n`
-                  + `Index: ${commit.index}`;
-            }
-          }
-        }
+        tooltip: tooltip
       },
       responsive: true,
       scales: scales.get()
diff --git a/tools/perf/dom.js b/tools/perf/dom.js
index fd5cdc9..301805f 100644
--- a/tools/perf/dom.js
+++ b/tools/perf/dom.js
@@ -3,9 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 import chart from "./chart.js";
 import state from "./state.js";
+import url from "./url.js";
 
 // DOM references.
 const benchmarkSelectors = document.getElementById('benchmark-selectors');
+const branchMain = document.getElementById('branch-main');
+const branchRelease = document.getElementById('branch-release');
 const canvas = document.getElementById('myChart');
 const runtimeMin = document.getElementById('runtime-min');
 const runtimeP50 = document.getElementById('runtime-p50');
@@ -17,6 +20,17 @@
 const showLessRight = document.getElementById('show-less-right');
 const showMoreRight = document.getElementById('show-more-right');
 
+function getSelectedBranch() {
+  console.assert(branchMain.checked || branchRelease.checked);
+  return branchMain.checked ? 'main' : 'release';
+}
+
+function initialize() {
+  initializeBenchmarkSelectors();
+  initializeBranchSelectors();
+  initializeChartNavigation();
+}
+
 function initializeBenchmarkSelectors() {
   state.forEachBenchmark(
     (benchmark, selected) => {
@@ -45,16 +59,25 @@
     });
 }
 
+function initializeBranchSelectors() {
+  if (url.contains('release')) {
+    branchRelease.checked = true;
+  }
+}
+
 function initializeChartNavigation() {
   const zoom = state.zoom;
 
+  branchMain.onclick = event => { state.resetZoom(); chart.update(true, false); };
+  branchRelease.onclick = event => { state.resetZoom(); chart.update(true, false); };
+
   canvas.onclick = event => {
     const points =
         chart.get().getElementsAtEventForMode(
             event, 'nearest', { intersect: true }, true);
     if (points.length > 0) {
       const point = points[0];
-      const commit = state.commits[point.index];
+      const commit = state.getCommit(point.index, null);
       window.open('https://r8.googlesource.com/r8/+/' + commit.hash, '_blank');
     }
   };
@@ -108,6 +131,14 @@
   };
 }
 
+function isCommitSelected(commit) {
+  if (branchRelease.checked) {
+    return commit.version;
+  } else {
+    return !commit.version;
+  }
+}
+
 function transformRuntimeData(results) {
   if (runtimeMin.checked) {
     return results.min();
@@ -144,8 +175,9 @@
 
 export default {
   canvas: canvas,
-  initializeBenchmarkSelectors: initializeBenchmarkSelectors,
-  initializeChartNavigation: initializeChartNavigation,
+  getSelectedBranch: getSelectedBranch,
+  initialize: initialize,
+  isCommitSelected: isCommitSelected,
   transformRuntimeData: transformRuntimeData,
   updateBenchmarkColors: updateBenchmarkColors,
   updateChartNavigation: updateChartNavigation
diff --git a/tools/perf/r8.html b/tools/perf/r8.html
index a992005..f4c530b 100644
--- a/tools/perf/r8.html
+++ b/tools/perf/r8.html
@@ -18,6 +18,12 @@
     <input type="radio" id="runtime-max" name="runtime-fn">
     <label for="runtime-max">Max</label>
   </div>
+  <div id="branch-selector">
+    <input type="radio" id="branch-main" name="branch-selector" checked>
+    <label for="branch-main">Main</label>
+    <input type="radio" id="branch-release" name="branch-selector">
+    <label for="branch-release">Release</label>
+  </div>
   <div id="benchmark-selectors"></div>
   <div>
       <canvas id="myChart"></canvas>
@@ -41,6 +47,7 @@
     import dom from "./dom.js";
     import scales from "./scales.js";
     import state from "./state.js";
+    import tooltip from "./tooltip.js";
 
     const commits = await state.importCommits("./r8_benchmark_data.json");
     state.initializeBenchmarks();
@@ -55,8 +62,7 @@
       'Warmup': { default: false }
     });
     state.initializeZoom();
-    dom.initializeBenchmarkSelectors();
-    dom.initializeChartNavigation();
+    dom.initialize();
 
     // Chart data provider.
     function getData(filteredCommits) {
@@ -333,37 +339,7 @@
             chart.update(false, true);
           },
         },
-        tooltip: {
-          callbacks: {
-            title: context => {
-              const elementInfo = context[0];
-              var commit;
-              if (elementInfo.dataset.type == 'line') {
-                commit = commits[state.zoom.left + elementInfo.dataIndex];
-              } else {
-                console.assert(elementInfo.dataset.type == 'scatter');
-                commit = commits[elementInfo.raw.x];
-              }
-              return commit.title;
-            },
-            footer: context => {
-              const elementInfo = context[0];
-              var commit;
-              if (elementInfo.dataset.type == 'line') {
-                commit = commits[state.zoom.left + elementInfo.dataIndex];
-              } else {
-                console.assert(elementInfo.dataset.type == 'scatter');
-                commit = commits[elementInfo.raw.x];
-              }
-              const dataset = chart.get().data.datasets[elementInfo.datasetIndex];
-              return `App: ${dataset.benchmark}\n`
-                  + `Author: ${commit.author}\n`
-                  + `Submitted: ${new Date(commit.submitted * 1000).toLocaleString()}\n`
-                  + `Hash: ${commit.hash}\n`
-                  + `Index: ${commit.index}`;
-            }
-          }
-        }
+        tooltip: tooltip
       },
       responsive: true,
       scales: scales.get()
diff --git a/tools/perf/retrace.html b/tools/perf/retrace.html
index b6331c6..e8740bb 100644
--- a/tools/perf/retrace.html
+++ b/tools/perf/retrace.html
@@ -18,6 +18,12 @@
     <input type="radio" id="runtime-max" name="runtime-fn">
     <label for="runtime-max">Max</label>
   </div>
+  <div id="branch-selector">
+    <input type="radio" id="branch-main" name="branch-selector" checked>
+    <label for="branch-main">Main</label>
+    <input type="radio" id="branch-release" name="branch-selector">
+    <label for="branch-release">Release</label>
+  </div>
   <div id="benchmark-selectors"></div>
   <div>
       <canvas id="myChart"></canvas>
@@ -41,6 +47,7 @@
     import dom from "./dom.js";
     import scales from "./scales.js";
     import state from "./state.js";
+    import tooltip from "./tooltip.js";
 
     const commits = await state.importCommits("./retrace_benchmark_data.json");
     state.initializeBenchmarks();
@@ -50,8 +57,7 @@
       'Warmup': { default: false }
     });
     state.initializeZoom();
-    dom.initializeBenchmarkSelectors();
-    dom.initializeChartNavigation();
+    dom.initialize();
 
     // Chart data provider.
     function getData(filteredCommits) {
@@ -200,37 +206,7 @@
             chart.update(false, true);
           },
         },
-        tooltip: {
-          callbacks: {
-            title: context => {
-              const elementInfo = context[0];
-              var commit;
-              if (elementInfo.dataset.type == 'line') {
-                commit = commits[state.zoom.left + elementInfo.dataIndex];
-              } else {
-                console.assert(elementInfo.dataset.type == 'scatter');
-                commit = commits[elementInfo.raw.x];
-              }
-              return commit.title;
-            },
-            footer: context => {
-              const elementInfo = context[0];
-              var commit;
-              if (elementInfo.dataset.type == 'line') {
-                commit = commits[state.zoom.left + elementInfo.dataIndex];
-              } else {
-                console.assert(elementInfo.dataset.type == 'scatter');
-                commit = commits[elementInfo.raw.x];
-              }
-              const dataset = chart.get().data.datasets[elementInfo.datasetIndex];
-              return `App: ${dataset.benchmark}\n`
-                  + `Author: ${commit.author}\n`
-                  + `Submitted: ${new Date(commit.submitted * 1000).toLocaleString()}\n`
-                  + `Hash: ${commit.hash}\n`
-                  + `Index: ${commit.index}`;
-            }
-          }
-        }
+        tooltip: tooltip
       },
       responsive: true,
       scales: scales.get()
diff --git a/tools/perf/state.js b/tools/perf/state.js
index ed07b39..d469238 100644
--- a/tools/perf/state.js
+++ b/tools/perf/state.js
@@ -1,6 +1,8 @@
 // Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+import chart from "./chart.js";
+import dom from "./dom.js";
 import url from "./url.js";
 
 var commits = null;
@@ -27,6 +29,41 @@
   });
 }
 
+function getCommit(index, zoom) {
+  return getCommits(zoom)[index];
+}
+
+function getCommitFromContext(context) {
+  const elementInfo = context[0];
+  var commit;
+  if (elementInfo.dataset.type == 'line') {
+    commit = getCommit(elementInfo.dataIndex, zoom);
+  } else {
+    console.assert(elementInfo.dataset.type == 'scatter');
+    commit = getCommit(elementInfo.raw.x, null);
+  }
+  return commit;
+}
+
+function getCommitDescriptionFromContext(context) {
+  const commit = getCommitFromContext(context);
+  const elementInfo = context[0];
+  const dataset = chart.get().data.datasets[elementInfo.datasetIndex];
+  return `App: ${dataset.benchmark}\n`
+      + `Author: ${commit.author}\n`
+      + `Submitted: ${new Date(commit.submitted * 1000).toLocaleString()}\n`
+      + `Hash: ${commit.hash}\n`
+      + `Index: ${commit.index}`;
+}
+
+function getCommits(zoom) {
+  const commitsForSelectedBranch = commits.filter(commit => dom.isCommitSelected(commit));
+  if (zoom) {
+    return commitsForSelectedBranch.slice(zoom.left, zoom.right);
+  }
+  return commitsForSelectedBranch;
+}
+
 function hasLegend(legend) {
   return legends.has(legend);
 }
@@ -37,8 +74,15 @@
         commits = module.default;
         commits.reverseInPlace();
         // Amend the commits with their unique index.
+        var mainIndex = 0;
+        var releaseIndex = 0;
         for (var i = 0; i < commits.length; i++) {
-          commits[i].index = i;
+          const commit = commits[i];
+          if (commit.version) {
+            commit.index = releaseIndex++;
+          } else {
+            commit.index = mainIndex++;
+          }
         }
         return commits;
       });
@@ -79,19 +123,18 @@
 }
 
 function initializeZoom() {
-  zoom.left = Math.max(0, commits.length - 75);
-  zoom.right = commits.length;
+  const filteredCommits = resetZoom();
   for (const urlOption of url.values()) {
     if (urlOption.startsWith('L')) {
       var left = parseInt(urlOption.substring(1));
       if (isNaN(left)) {
         continue;
       }
-      left = left >= 0 ? left : commits.length + left;
+      left = left >= 0 ? left : filteredCommits.length + left;
       if (left < 0) {
         zoom.left = 0;
-      } else if (left >= commits.length) {
-        zoom.left = commits.length - 1;
+      } else if (left >= filteredCommits.length) {
+        zoom.left = filteredCommits.length - 1;
       } else {
         zoom.left = left;
       }
@@ -99,6 +142,13 @@
   }
 }
 
+function resetZoom() {
+  const filteredCommits = getCommits(null);
+  zoom.left = Math.max(0, filteredCommits.length - 75);
+  zoom.right = filteredCommits.length;
+  return filteredCommits;
+}
+
 function handleKeyDownEvent(e, callback) {
   if (selectedBenchmarks.size != 1) {
     return;
@@ -133,12 +183,15 @@
 
 export default {
   benchmarks: benchmarks,
-  commits: zoom => zoom ? commits.slice(zoom.left, zoom.right) : commits,
+  commits: getCommits,
   legends: legends,
   selectedBenchmarks: selectedBenchmarks,
   selectedLegends: selectedLegends,
   forEachBenchmark: forEachBenchmark,
   forEachSelectedBenchmark: forEachSelectedBenchmark,
+  getCommit: getCommit,
+  getCommitFromContext: getCommitFromContext,
+  getCommitDescriptionFromContext: getCommitDescriptionFromContext,
   handleKeyDownEvent: handleKeyDownEvent,
   hasLegend: hasLegend,
   initializeBenchmarks: initializeBenchmarks,
@@ -146,5 +199,6 @@
   initializeZoom: initializeZoom,
   importCommits: importCommits,
   isLegendSelected: isLegendSelected,
+  resetZoom: resetZoom,
   zoom: zoom
 };
diff --git a/tools/perf/stylesheet.css b/tools/perf/stylesheet.css
index de995cf..11b75c2 100644
--- a/tools/perf/stylesheet.css
+++ b/tools/perf/stylesheet.css
@@ -4,4 +4,5 @@
   font-family: 'Roboto';
 }
 
+div#branch-selector { border-right: 1px grey solid; float: right; margin-right: 20pt; padding-right: 20pt; }
 div#runtime-fn { float: right; }
diff --git a/tools/perf/tooltip.js b/tools/perf/tooltip.js
new file mode 100644
index 0000000..1d704a1
--- /dev/null
+++ b/tools/perf/tooltip.js
@@ -0,0 +1,11 @@
+// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import state from "./state.js";
+
+export default {
+  callbacks: {
+    title: context => state.getCommitFromContext(context).title,
+    footer: context => state.getCommitDescriptionFromContext(context)
+  }
+};
diff --git a/tools/perf/url.js b/tools/perf/url.js
index f00a2f77..cf3b754 100644
--- a/tools/perf/url.js
+++ b/tools/perf/url.js
@@ -1,6 +1,8 @@
 // Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+import dom from "./dom.js";
+
 const options = unescape(window.location.hash.substring(1)).split(',');
 
 function contains(subject) {
@@ -26,6 +28,7 @@
               state.selectedLegends.size == state.legends.size
                   ? []
                   : Array.from(state.selectedLegends))
+          .concat(dom.getSelectedBranch() == 'release' ? ['release'] : [])
           .join(',');
 }
 
diff --git a/tools/upload_benchmark_data_to_google_storage.py b/tools/upload_benchmark_data_to_google_storage.py
index 4aa7b8e..8570e8b 100755
--- a/tools/upload_benchmark_data_to_google_storage.py
+++ b/tools/upload_benchmark_data_to_google_storage.py
@@ -19,7 +19,8 @@
 
 FILES = [
     'chart.js', 'd8.html', 'dom.js', 'extensions.js', 'r8.html', 'retrace.html',
-    'scales.js', 'state.js', 'stylesheet.css', 'url.js', 'utils.js'
+    'scales.js', 'state.js', 'stylesheet.css', 'tooltip.js', 'url.js',
+    'utils.js'
 ]