Merge "tp: make chrome threads test deterministic"
diff --git a/protos/perfetto/metrics/android/startup_metric.proto b/protos/perfetto/metrics/android/startup_metric.proto
index c4b44e0..c1ac949 100644
--- a/protos/perfetto/metrics/android/startup_metric.proto
+++ b/protos/perfetto/metrics/android/startup_metric.proto
@@ -47,8 +47,12 @@
   // activity manager to the first frame drawn.
   // Next id: 29.
   message ToFirstFrame {
+    // The duration between the intent received and first frame.
     optional int64 dur_ns = 1;
     optional double dur_ms = 17;
+
+    // Breakdown of time to first frame by task state for the main thread of
+    // the process starting up.
     optional TaskStateBreakdown main_thread_by_task_state = 2;
 
     // The mcycles taken by this startup across all CPUs (broken down by core
@@ -130,7 +134,14 @@
     optional string location = 4;
   }
 
-  // Next id: 13
+  // Contains timestamps of important events which occurred during the
+  // startup.
+  message EventTimestamps {
+    optional int64 intent_received = 1;
+    optional int64 first_frame = 2;
+  }
+
+  // Next id: 14
   message Startup {
     // Random id uniquely identifying an app startup in this trace.
     optional uint32 startup_id = 1;
@@ -153,11 +164,19 @@
     // it.
     optional uint32 activity_hosting_process_count = 6;
 
+    // Contains timestamps of important events which happened during
+    // the startup.
+    optional EventTimestamps event_timestamps = 13;
+
+    // Timing information spanning the intent received by the
+    // activity manager to the first frame drawn.
     optional ToFirstFrame to_first_frame = 5;
 
     // Details about the process (uid, version, etc)
     optional AndroidProcessMetadata process = 7;
 
+    // Metrics about startup which were developed by looking at experiments
+    // using high-speed cameras (HSC).
     optional HscMetrics hsc = 8;
 
     // The time taken in the startup from intent recieved to the start time
@@ -165,6 +184,7 @@
     // first frame as the application decides this after it starts rendering.
     optional Slice report_fully_drawn = 9;
 
+    // Conntains information about the status of odex files.
     repeated OptimizationStatus optimization_status = 12;
 
     reserved 10;
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 55419c7..4f77dcb 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -722,8 +722,12 @@
   // activity manager to the first frame drawn.
   // Next id: 29.
   message ToFirstFrame {
+    // The duration between the intent received and first frame.
     optional int64 dur_ns = 1;
     optional double dur_ms = 17;
+
+    // Breakdown of time to first frame by task state for the main thread of
+    // the process starting up.
     optional TaskStateBreakdown main_thread_by_task_state = 2;
 
     // The mcycles taken by this startup across all CPUs (broken down by core
@@ -805,7 +809,14 @@
     optional string location = 4;
   }
 
-  // Next id: 13
+  // Contains timestamps of important events which occurred during the
+  // startup.
+  message EventTimestamps {
+    optional int64 intent_received = 1;
+    optional int64 first_frame = 2;
+  }
+
+  // Next id: 14
   message Startup {
     // Random id uniquely identifying an app startup in this trace.
     optional uint32 startup_id = 1;
@@ -828,11 +839,19 @@
     // it.
     optional uint32 activity_hosting_process_count = 6;
 
+    // Contains timestamps of important events which happened during
+    // the startup.
+    optional EventTimestamps event_timestamps = 13;
+
+    // Timing information spanning the intent received by the
+    // activity manager to the first frame drawn.
     optional ToFirstFrame to_first_frame = 5;
 
     // Details about the process (uid, version, etc)
     optional AndroidProcessMetadata process = 7;
 
+    // Metrics about startup which were developed by looking at experiments
+    // using high-speed cameras (HSC).
     optional HscMetrics hsc = 8;
 
     // The time taken in the startup from intent recieved to the start time
@@ -840,6 +859,7 @@
     // first frame as the application decides this after it starts rendering.
     optional Slice report_fully_drawn = 9;
 
+    // Conntains information about the status of odex files.
     repeated OptimizationStatus optimization_status = 12;
 
     reserved 10;
diff --git a/src/trace_processor/metrics/android/android_startup.sql b/src/trace_processor/metrics/android/android_startup.sql
index b9960e1..364a635 100644
--- a/src/trace_processor/metrics/android/android_startup.sql
+++ b/src/trace_processor/metrics/android/android_startup.sql
@@ -243,6 +243,10 @@
       SELECT COUNT(1) FROM launch_processes p
       WHERE p.launch_id = launches.id
     ),
+    'event_timestamps', AndroidStartupMetric_EventTimestamps(
+      'intent_received', launches.ts,
+      'first_frame', launches.ts_end
+    ),
     'to_first_frame', AndroidStartupMetric_ToFirstFrame(
       'dur_ns', launches.dur,
       'dur_ms', launches.dur / 1e6,
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
index 8cf5c7c..3db9029 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/test/trace_processor/startup/android_startup.out b/test/trace_processor/startup/android_startup.out
index bef8217..a7dd383 100644
--- a/test/trace_processor/startup/android_startup.out
+++ b/test/trace_processor/startup/android_startup.out
@@ -40,5 +40,9 @@
       dur_ns: 198
       dur_ms: 0.000198
     }
+    event_timestamps {
+      intent_received: 102
+      first_frame: 210
+    }
   }
 }
diff --git a/test/trace_processor/startup/android_startup_attribution.out b/test/trace_processor/startup/android_startup_attribution.out
index fb2cdf5..e48e3db 100644
--- a/test/trace_processor/startup/android_startup_attribution.out
+++ b/test/trace_processor/startup/android_startup_attribution.out
@@ -38,5 +38,9 @@
     process {
       name: "com.some.app"
     }
+    event_timestamps {
+      intent_received: 100
+      first_frame: 300
+    }
   }
 }
diff --git a/test/trace_processor/startup/android_startup_breakdown.out b/test/trace_processor/startup/android_startup_breakdown.out
index e6c360e..298773d 100644
--- a/test/trace_processor/startup/android_startup_breakdown.out
+++ b/test/trace_processor/startup/android_startup_breakdown.out
@@ -70,5 +70,9 @@
       compilation_reason: "unknown"
       location: "error"
     }
+    event_timestamps {
+      intent_received: 102000000000
+      first_frame: 210000000000
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/test/trace_processor/startup/android_startup_process_track.out b/test/trace_processor/startup/android_startup_process_track.out
index 817b19d..357603d 100644
--- a/test/trace_processor/startup/android_startup_process_track.out
+++ b/test/trace_processor/startup/android_startup_process_track.out
@@ -24,6 +24,10 @@
       }
       dur_ms: 4e-06
     }
+    event_timestamps {
+      intent_received: 100
+      first_frame: 104
+    }
     activity_hosting_process_count: 1
   }
   startup {
@@ -51,6 +55,10 @@
       }
       dur_ms: 4e-06
     }
+    event_timestamps {
+      intent_received: 200
+      first_frame: 204
+    }
     activity_hosting_process_count: 1
   }
 }
diff --git a/ui/src/tracks/counter/common.ts b/ui/src/tracks/counter/common.ts
index 3751161..876eaf0 100644
--- a/ui/src/tracks/counter/common.ts
+++ b/ui/src/tracks/counter/common.ts
@@ -16,7 +16,7 @@
 
 export const COUNTER_TRACK_KIND = 'CounterTrack';
 
-export type CounterScaleOptions = 'DEFAULT'|'RELATIVE'|'DELTA';
+export type CounterScaleOptions = 'ZERO_BASED'|'MIN_MAX'|'DELTA_FROM_PREVIOUS';
 
 export interface Data extends TrackData {
   maximumValue: number;
diff --git a/ui/src/tracks/counter/frontend.ts b/ui/src/tracks/counter/frontend.ts
index 6592dbb..186b1e1 100644
--- a/ui/src/tracks/counter/frontend.ts
+++ b/ui/src/tracks/counter/frontend.ts
@@ -36,38 +36,46 @@
 const MARGIN_TOP = 3.5;
 const RECT_HEIGHT = 24.5;
 
+interface CounterScaleAttribute {
+  follower: CounterScaleOptions;
+  tooltip: string;
+  icon: string;
+}
+
 function scaleTooltip(scale?: CounterScaleOptions): string {
-  switch (scale) {
-    case 'RELATIVE':
-      return 'Use zero-based scale';
-    case 'DELTA':
-      return 'Use delta scale';
-    case 'DEFAULT':
-    default:
-      return 'Use zero-based scale';
-  }
+  const description: CounterScaleAttribute = getCounterScaleAttribute(scale);
+  const source: string = description.tooltip;
+  const destination: string =
+      getCounterScaleAttribute(description.follower).tooltip;
+  return `Toggle scale from ${source} to ${destination}`;
 }
 
 function scaleIcon(scale?: CounterScaleOptions): string {
-  switch (scale) {
-    case 'DELTA':
-      return 'bar_chart';
-    case 'RELATIVE':
-    case 'DEFAULT':
-    default:
-      return 'show_chart';
-  }
+  return getCounterScaleAttribute(scale).icon;
 }
 
 function nextScale(scale?: CounterScaleOptions): CounterScaleOptions {
+  return getCounterScaleAttribute(scale).follower;
+}
+
+function getCounterScaleAttribute(scale?: CounterScaleOptions):
+    CounterScaleAttribute {
   switch (scale) {
-    case 'RELATIVE':
-      return 'DELTA';
-    case 'DELTA':
-      return 'DEFAULT';
-    case 'DEFAULT':
+    case 'MIN_MAX':
+      return {
+        follower: 'DELTA_FROM_PREVIOUS',
+        tooltip: 'min/max',
+        icon: 'show_chart'
+      };
+    case 'DELTA_FROM_PREVIOUS':
+      return {follower: 'ZERO_BASED', tooltip: 'delta', icon: 'bar_chart'};
+    case 'ZERO_BASED':
     default:
-      return 'RELATIVE';
+      return {
+        follower: 'MIN_MAX',
+        tooltip: 'zero based',
+        icon: 'waterfall_chart'
+      };
   }
 }
 
@@ -101,7 +109,7 @@
       },
       i: scaleIcon(this.config.scale),
       tooltip: scaleTooltip(this.config.scale),
-      showButton: !!this.config.scale && this.config.scale !== 'DEFAULT',
+      showButton: !!this.config.scale && this.config.scale !== 'ZERO_BASED',
     }));
     return buttons;
   }
@@ -121,14 +129,14 @@
     assertTrue(data.timestamps.length === data.lastValues.length);
     assertTrue(data.timestamps.length === data.totalDeltas.length);
 
-    const scale: CounterScaleOptions = this.config.scale || 'DEFAULT';
+    const scale: CounterScaleOptions = this.config.scale || 'ZERO_BASED';
 
     let minValues = data.minValues;
     let maxValues = data.maxValues;
     let lastValues = data.lastValues;
     let maximumValue = data.maximumValue;
     let minimumValue = data.minimumValue;
-    if (scale === 'DELTA') {
+    if (scale === 'DELTA_FROM_PREVIOUS') {
       lastValues = data.totalDeltas;
       minValues = data.totalDeltas;
       maxValues = data.totalDeltas;
@@ -151,7 +159,7 @@
     const unitGroup = Math.floor(exp / 3);
     let yMin = 0;
     let yLabel = '';
-    if (scale === 'RELATIVE') {
+    if (scale === 'MIN_MAX') {
       yRange = maximumValue - minimumValue;
       yMin = minimumValue;
       yLabel = 'min - max';
@@ -159,7 +167,7 @@
       yRange = minimumValue < 0 ? yMax * 2 : yMax;
       yMin = minimumValue < 0 ? -yMax : 0;
       yLabel = `${yMax / Math.pow(10, unitGroup * 3)} ${kUnits[unitGroup]}`;
-      if (scale === 'DELTA') {
+      if (scale === 'DELTA_FROM_PREVIOUS') {
         yLabel += '\u0394';
       }
     }
@@ -226,7 +234,7 @@
 
     if (this.hoveredValue !== undefined && this.hoveredTs !== undefined) {
       // TODO(hjd): Add units.
-      let text = scale === 'DELTA' ? 'delta: ' : 'value: ';
+      let text = scale === 'DELTA_FROM_PREVIOUS' ? 'delta: ' : 'value: ';
       text += `${this.hoveredValue.toLocaleString()}`;
 
       ctx.fillStyle = `hsl(${hue}, 45%, 75%)`;
@@ -296,8 +304,9 @@
     const {timeScale} = globals.frontendLocalState;
     const time = timeScale.pxToTime(x);
 
-    const values =
-        this.config.scale === 'DELTA' ? data.totalDeltas : data.lastValues;
+    const values = this.config.scale === 'DELTA_FROM_PREVIOUS' ?
+        data.totalDeltas :
+        data.lastValues;
     const [left, right] = searchSegment(data.timestamps, time);
     this.hoveredTs = left === -1 ? undefined : data.timestamps[left];
     this.hoveredTsEnd = right === -1 ? undefined : data.timestamps[right];