Show warmup in perf

Change-Id: I522619ee27b8499cac6d611ba5a99f98b68d181b
diff --git a/tools/perf/d8.html b/tools/perf/d8.html
index d495324..848ceea 100644
--- a/tools/perf/d8.html
+++ b/tools/perf/d8.html
@@ -48,7 +48,8 @@
       'Dex size': { default: true },
       'Nondeterminism': { default: true },
       'Runtime': { default: true },
-      'Runtime variance': { default: false }
+      'Runtime variance': { default: false },
+      'Warmup': { default: false }
     });
     state.initializeZoom();
     dom.initializeBenchmarkSelectors();
@@ -89,11 +90,9 @@
           const runtimeData =
               filteredCommits.map(
                   (c, i) =>
-                      selectedBenchmark in filteredCommits[i].benchmarks
-                          ? getAllResults(selectedBenchmark, filteredCommits[i], "runtime",
-                                results => dom.transformRuntimeData(results))
-                              .ns_to_s()
-                          : NaN);
+                      getAllResults(
+                          selectedBenchmark, filteredCommits[i], "runtime",
+                          results => dom.transformRuntimeData(results).ns_to_s()));
           const runtimeScatterData = [];
           for (const commit of filteredCommits.values()) {
             if (!(selectedBenchmark in commit.benchmarks)) {
@@ -104,6 +103,12 @@
               runtimeScatterData.push({ x: commit.index, y: runtime.ns_to_s() });
             }
           }
+          const warmupData =
+              filteredCommits.map(
+                  (c, i) =>
+                      getAllWarmupResults(
+                          selectedBenchmark, filteredCommits[i], "runtime",
+                          results => dom.transformRuntimeData(results).ns_to_s()));
 
           const skipped = (ctx, value) => ctx.p0.skip || ctx.p1.skip ? value : undefined;
           datasets.push(...[
@@ -176,6 +181,29 @@
                 }
               },
               yAxisID: 'y_runtime'
+            },
+            {
+              benchmark: selectedBenchmark,
+              type: 'line',
+              label: 'Warmup',
+              data: warmupData,
+              datalabels: {
+                labels: {
+                  value: null
+                }
+              },
+              tension: 0.1,
+              yAxisID: 'y_runtime',
+              segment: {
+                borderColor: ctx =>
+                    skipped(
+                        ctx,
+                        chart.get()
+                            ? chart.get().data.datasets[ctx.datasetIndex].backgroundColor
+                            : undefined),
+                borderDash: ctx => skipped(ctx, [6, 6]),
+              },
+              spanGaps: true
             }
           ]);
         });
diff --git a/tools/perf/r8.html b/tools/perf/r8.html
index 23b6c7b..a992005 100644
--- a/tools/perf/r8.html
+++ b/tools/perf/r8.html
@@ -51,7 +51,8 @@
       'Oat size': { default: true },
       'Nondeterminism': { default: true },
       'Runtime': { default: true },
-      'Runtime variance': { default: false }
+      'Runtime variance': { default: false },
+      'Warmup': { default: false }
     });
     state.initializeZoom();
     dom.initializeBenchmarkSelectors();
@@ -101,11 +102,9 @@
           const runtimeData =
               filteredCommits.map(
                   (c, i) =>
-                      selectedBenchmark in filteredCommits[i].benchmarks
-                          ? getAllResults(selectedBenchmark, filteredCommits[i], "runtime",
-                                results => dom.transformRuntimeData(results))
-                              .ns_to_s()
-                          : NaN);
+                      getAllResults(
+                          selectedBenchmark, filteredCommits[i], "runtime",
+                          results => dom.transformRuntimeData(results).ns_to_s()));
           const runtimeScatterData = [];
           for (const commit of filteredCommits.values()) {
             if (!(selectedBenchmark in commit.benchmarks)) {
@@ -116,6 +115,12 @@
               runtimeScatterData.push({ x: commit.index, y: runtime.ns_to_s() });
             }
           }
+          const warmupData =
+              filteredCommits.map(
+                  (c, i) =>
+                      getAllWarmupResults(
+                          selectedBenchmark, filteredCommits[i], "runtime",
+                          results => dom.transformRuntimeData(results).ns_to_s()));
 
           const skipped = (ctx, value) => ctx.p0.skip || ctx.p1.skip ? value : undefined;
           datasets.push(...[
@@ -254,6 +259,29 @@
                 }
               },
               yAxisID: 'y_runtime'
+            },
+            {
+              benchmark: selectedBenchmark,
+              type: 'line',
+              label: 'Warmup',
+              data: warmupData,
+              datalabels: {
+                labels: {
+                  value: null
+                }
+              },
+              tension: 0.1,
+              yAxisID: 'y_runtime',
+              segment: {
+                borderColor: ctx =>
+                    skipped(
+                        ctx,
+                        chart.get()
+                            ? chart.get().data.datasets[ctx.datasetIndex].backgroundColor
+                            : undefined),
+                borderDash: ctx => skipped(ctx, [6, 6]),
+              },
+              spanGaps: true
             }
           ]);
         });
diff --git a/tools/perf/retrace.html b/tools/perf/retrace.html
index 7437025..b6331c6 100644
--- a/tools/perf/retrace.html
+++ b/tools/perf/retrace.html
@@ -46,7 +46,8 @@
     state.initializeBenchmarks();
     state.initializeLegends({
       'Runtime': { default: true },
-      'Runtime variance': { default: true }
+      'Runtime variance': { default: true },
+      'Warmup': { default: false }
     });
     state.initializeZoom();
     dom.initializeBenchmarkSelectors();
@@ -69,11 +70,9 @@
           const runtimeData =
               filteredCommits.map(
                   (c, i) =>
-                      selectedBenchmark in filteredCommits[i].benchmarks
-                          ? getAllResults(selectedBenchmark, filteredCommits[i], "runtime",
-                                results => dom.transformRuntimeData(results))
-                              .ns_to_s()
-                          : NaN);
+                      getAllResults(
+                          selectedBenchmark, filteredCommits[i], "runtime",
+                          results => dom.transformRuntimeData(results).ns_to_s()));
           const runtimeScatterData = [];
           for (const commit of filteredCommits.values()) {
             if (!(selectedBenchmark in commit.benchmarks)) {
@@ -84,6 +83,12 @@
               runtimeScatterData.push({ x: commit.index, y: runtime.ns_to_s() });
             }
           }
+          const warmupData =
+              filteredCommits.map(
+                  (c, i) =>
+                      getAllWarmupResults(
+                          selectedBenchmark, filteredCommits[i], "runtime",
+                          results => dom.transformRuntimeData(results).ns_to_s()));
 
           const skipped = (ctx, value) => ctx.p0.skip || ctx.p1.skip ? value : undefined;
           datasets.push(...[
@@ -121,6 +126,29 @@
                 }
               },
               yAxisID: 'y_runtime'
+            },
+            {
+              benchmark: selectedBenchmark,
+              type: 'line',
+              label: 'Warmup',
+              data: warmupData,
+              datalabels: {
+                labels: {
+                  value: null
+                }
+              },
+              tension: 0.1,
+              yAxisID: 'y_runtime',
+              segment: {
+                borderColor: ctx =>
+                    skipped(
+                        ctx,
+                        chart.get()
+                            ? chart.get().data.datasets[ctx.datasetIndex].backgroundColor
+                            : undefined),
+                borderDash: ctx => skipped(ctx, [6, 6]),
+              },
+              spanGaps: true
             }
           ]);
         });
diff --git a/tools/perf/scales.js b/tools/perf/scales.js
index 8378e2f..bd3226a 100644
--- a/tools/perf/scales.js
+++ b/tools/perf/scales.js
@@ -21,6 +21,7 @@
   }
   console.assert(state.hasLegend('Runtime'));
   console.assert(state.hasLegend('Runtime variance'));
+  console.assert(state.hasLegend('Warmup'));
   scales.y_runtime = {
     position: state.hasLegend('Dex size') ? 'right' : 'left',
     title: {
@@ -62,7 +63,9 @@
   }
   if (scales.y_runtime) {
     scales.y_runtime.display =
-        state.isLegendSelected('Runtime') || state.isLegendSelected('Runtime variance');
+        state.isLegendSelected('Runtime')
+            || state.isLegendSelected('Runtime variance')
+            || state.isLegendSelected('Warmup');
   }
 }
 
diff --git a/tools/perf/utils.js b/tools/perf/utils.js
index 13cd09c..e699f32 100644
--- a/tools/perf/utils.js
+++ b/tools/perf/utils.js
@@ -1,11 +1,12 @@
 // 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.
-function getSingleResult(benchmark, commit, resultName, resultIteration = 0) {
+function getSingleResult(benchmark, commit, resultName, resultIteration = 0, warmup = false) {
   if (!(benchmark in commit.benchmarks)) {
     return NaN;
   }
-  const allResults = commit.benchmarks[benchmark].results;
+  const benchmarkData = commit.benchmarks[benchmark];
+  const allResults = warmup ? benchmarkData.warmup : benchmarkData.results;
   const resultsForIteration = allResults[resultIteration];
   // If a given iteration does not declare a result, then the result
   // was the same as the first run.
@@ -15,14 +16,25 @@
   return resultsForIteration[resultName];
 }
 
-function getAllResults(benchmark, commit, resultName, transformation) {
+function getAllResults(benchmark, commit, resultName, transformation, warmup = false) {
+  if (!(benchmark in commit.benchmarks)) {
+    return NaN;
+  }
+  const benchmarkData = commit.benchmarks[benchmark];
+  if (warmup && !('warmup' in benchmarkData)) {
+    return NaN;
+  }
   const result = [];
-  const allResults = commit.benchmarks[benchmark].results;
+  const allResults = warmup ? benchmarkData.warmup : benchmarkData.results;
   for (var iteration = 0; iteration < allResults.length; iteration++) {
-    result.push(getSingleResult(benchmark, commit, resultName, iteration));
+    result.push(getSingleResult(benchmark, commit, resultName, iteration, warmup));
   }
   if (transformation) {
     return transformation(result);
   }
   return result;
 }
+
+function getAllWarmupResults(benchmark, commit, resultName, transformation) {
+  return getAllResults(benchmark, commit, resultName, transformation, true);
+}