metrics: add mcycles breakdown by core type to startup metric

This CL adds a per-core type mcycle counter for each startup.

Change-Id: I28135a8d45d575171df43b9577368447288f107d
Bug: 183956291
diff --git a/protos/perfetto/metrics/android/startup_metric.proto b/protos/perfetto/metrics/android/startup_metric.proto
index ecbd0a9..5d8fcf8 100644
--- a/protos/perfetto/metrics/android/startup_metric.proto
+++ b/protos/perfetto/metrics/android/startup_metric.proto
@@ -31,6 +31,13 @@
     optional int64 interruptible_sleep_dur_ns = 4;
   }
 
+  message McyclesByCoreType {
+    optional int64 little = 1;
+    optional int64 big = 2;
+    optional int64 bigger = 3;
+    optional int64 unknown = 4;
+  }
+
   message Slice {
     optional int64 dur_ns = 1;
     optional double dur_ms = 2;
@@ -38,12 +45,16 @@
 
   // Timing information spanning the intent received by the
   // activity manager to the first frame drawn.
-  // Next id: 26.
+  // Next id: 27.
   message ToFirstFrame {
     optional int64 dur_ns = 1;
     optional double dur_ms = 17;
     optional TaskStateBreakdown main_thread_by_task_state = 2;
 
+    // The mcycles taken by this startup across all CPUs (broken down by core
+    // type).
+    optional McyclesByCoreType mcycles_by_core_type = 26;
+
     // In this timespan, how many processes (apart from the main activity) were
     // spawned.
     optional uint32 other_processes_spawned_count = 3;
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 678c85e..5736909 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -706,6 +706,13 @@
     optional int64 interruptible_sleep_dur_ns = 4;
   }
 
+  message McyclesByCoreType {
+    optional int64 little = 1;
+    optional int64 big = 2;
+    optional int64 bigger = 3;
+    optional int64 unknown = 4;
+  }
+
   message Slice {
     optional int64 dur_ns = 1;
     optional double dur_ms = 2;
@@ -713,12 +720,16 @@
 
   // Timing information spanning the intent received by the
   // activity manager to the first frame drawn.
-  // Next id: 26.
+  // Next id: 27.
   message ToFirstFrame {
     optional int64 dur_ns = 1;
     optional double dur_ms = 17;
     optional TaskStateBreakdown main_thread_by_task_state = 2;
 
+    // The mcycles taken by this startup across all CPUs (broken down by core
+    // type).
+    optional McyclesByCoreType mcycles_by_core_type = 26;
+
     // In this timespan, how many processes (apart from the main activity) were
     // spawned.
     optional uint32 other_processes_spawned_count = 3;
diff --git a/src/trace_processor/metrics/android/android_startup.sql b/src/trace_processor/metrics/android/android_startup.sql
index 77745c4..808d7d3 100644
--- a/src/trace_processor/metrics/android/android_startup.sql
+++ b/src/trace_processor/metrics/android/android_startup.sql
@@ -19,6 +19,39 @@
 SELECT RUN_METRIC('android/process_metadata.sql');
 SELECT RUN_METRIC('android/hsc_startups.sql');
 
+-- Create the base CPU span join table.
+SELECT RUN_METRIC('android/android_cpu_agg.sql');
+
+-- Create a span join safe launches view; since both views
+-- being span joined have an "id" column, we need to rename
+-- the id column for launches to disambiguate the two.
+DROP VIEW IF EXISTS launches_span_join_safe;
+CREATE VIEW launches_span_join_safe AS
+SELECT ts, dur, id AS launch_id
+FROM launches;
+
+-- Span join the CPU table with the launches table to get the
+-- breakdown per-cpu.
+DROP TABLE IF EXISTS cpu_freq_sched_per_thread_per_launch;
+CREATE VIRTUAL TABLE cpu_freq_sched_per_thread_per_launch
+USING SPAN_JOIN(
+  launches_span_join_safe,
+  cpu_freq_sched_per_thread PARTITIONED cpu
+);
+
+SELECT RUN_METRIC('android/cpu_info.sql');
+
+DROP VIEW IF EXISTS mcycles_per_core_type_per_launch;
+CREATE VIEW mcycles_per_core_type_per_launch AS
+SELECT
+  launch_id,
+  IFNULL(core_type_per_cpu.core_type, 'unknown') AS core_type,
+  CAST(SUM(dur * freq_khz / 1000) / 1e9 AS INT) AS mcycles
+FROM cpu_freq_sched_per_thread_per_launch
+LEFT JOIN core_type_per_cpu USING (cpu)
+WHERE utid != 0
+GROUP BY 1, 2;
+
 -- Slices for forked processes. Never present in hot starts.
 -- Prefer this over process start_ts, since the process might have
 -- been preforked.
@@ -211,6 +244,28 @@
             WHERE l.launch_id = launches.id AND state = 'S'
             ), 0)
       ),
+      'mcycles_by_core_type', AndroidStartupMetric_McyclesByCoreType(
+        'little', (
+          SELECT mcycles
+          FROM mcycles_per_core_type_per_launch m
+          WHERE m.launch_id = launches.id AND m.core_type = 'little'
+        ),
+        'big', (
+          SELECT mcycles
+          FROM mcycles_per_core_type_per_launch m
+          WHERE m.launch_id = launches.id AND m.core_type = 'big'
+        ),
+        'bigger', (
+          SELECT mcycles
+          FROM mcycles_per_core_type_per_launch m
+          WHERE m.launch_id = launches.id AND m.core_type = 'bigger'
+        ),
+        'unknown', (
+          SELECT mcycles
+          FROM mcycles_per_core_type_per_launch m
+          WHERE m.launch_id = launches.id AND m.core_type = 'unknown'
+        )
+      ),
       'to_post_fork', (
         SELECT slice_proto
         FROM to_event_protos p
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
index c1af116..1155e2b 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 578295a..bef8217 100644
--- a/test/trace_processor/startup/android_startup.out
+++ b/test/trace_processor/startup/android_startup.out
@@ -32,6 +32,8 @@
         dur_ns: 8
         dur_ms: 8e-06
       }
+      mcycles_by_core_type {
+      }
       dur_ms: 0.000108
     }
     report_fully_drawn {
diff --git a/test/trace_processor/startup/android_startup_attribution.out b/test/trace_processor/startup/android_startup_attribution.out
index 22d4e4f..733dfc7 100644
--- a/test/trace_processor/startup/android_startup_attribution.out
+++ b/test/trace_processor/startup/android_startup_attribution.out
@@ -26,6 +26,8 @@
         dur_ns: 40
         dur_ms: 4e-05
       }
+      mcycles_by_core_type {
+      }
     }
     activity_hosting_process_count: 1
     process {
diff --git a/test/trace_processor/startup/android_startup_breakdown.out b/test/trace_processor/startup/android_startup_breakdown.out
index f29b01a..e6c360e 100644
--- a/test/trace_processor/startup/android_startup_breakdown.out
+++ b/test/trace_processor/startup/android_startup_breakdown.out
@@ -3,63 +3,59 @@
     startup_id: 1
     package_name: "com.google.android.calendar"
     process_name: "com.google.android.calendar"
-    process: {
+    zygote_new_process: true
+    to_first_frame {
+      dur_ns: 108000000000
+      main_thread_by_task_state {
+        running_dur_ns: 25000000000
+        runnable_dur_ns: 5000000000
+        uninterruptible_sleep_dur_ns: 0
+        interruptible_sleep_dur_ns: 0
+      }
+      other_processes_spawned_count: 0
+      time_activity_manager {
+        dur_ns: 8000000000
+        dur_ms: 8000
+      }
+      time_bind_application {
+        dur_ns: 9000000000
+        dur_ms: 9000
+      }
+      time_before_start_process {
+        dur_ns: 18000000000
+        dur_ms: 18000
+      }
+      time_during_start_process {
+        dur_ns: 35000000000
+        dur_ms: 35000
+      }
+      dur_ms: 108000
+      to_bind_application {
+        dur_ns: 83000000000
+        dur_ms: 83000
+      }
+      time_inflate {
+        dur_ns: 3000000000
+        dur_ms: 3000
+      }
+      time_get_resources {
+        dur_ns: 1000000000
+        dur_ms: 1000
+      }
+      mcycles_by_core_type {
+        unknown: 103
+      }
+    }
+    activity_hosting_process_count: 1
+    process {
       name: "com.google.android.calendar"
     }
     activities {
       name: "com.google.android.calendar.MainActivity"
       method: "performCreate"
       slice {
-        dur_ns: 4
-        dur_ms: 4e-06
-      }
-    }
-    activities {
-      name: "com.google.android.calendar.MainActivity"
-      method: "performResume"
-      slice {
-        dur_ns: 1
-        dur_ms: 1e-06
-      }
-    }
-    zygote_new_process: true
-    to_first_frame {
-      dur_ns: 108
-      main_thread_by_task_state {
-        running_dur_ns: 0
-        runnable_dur_ns: 0
-        uninterruptible_sleep_dur_ns: 0
-        interruptible_sleep_dur_ns: 0
-      }
-      other_processes_spawned_count: 0
-      time_activity_manager {
-        dur_ns: 8
-        dur_ms: 8e-06
-      }
-      time_bind_application {
-        dur_ns: 10
-        dur_ms: 1e-05
-      }
-      time_before_start_process {
-        dur_ns: 18
-        dur_ms: 1.8e-05
-      }
-      time_during_start_process {
-        dur_ns: 35
-        dur_ms: 3.5e-05
-      }
-      dur_ms: 0.000108
-      to_bind_application {
-        dur_ns: 83
-        dur_ms: 8.3e-05
-      }
-      time_inflate {
-        dur_ns: 3
-        dur_ms: 3e-06
-      }
-      time_get_resources {
-        dur_ns: 1
-        dur_ms: 1e-06
+        dur_ns: 4000000000
+        dur_ms: 4000
       }
     }
     optimization_status {
@@ -74,6 +70,5 @@
       compilation_reason: "unknown"
       location: "error"
     }
-    activity_hosting_process_count: 1
   }
-}
+}
\ No newline at end of file
diff --git a/test/trace_processor/startup/android_startup_breakdown.py b/test/trace_processor/startup/android_startup_breakdown.py
index 066d2fc..11df3e5 100644
--- a/test/trace_processor/startup/android_startup_breakdown.py
+++ b/test/trace_processor/startup/android_startup_breakdown.py
@@ -17,6 +17,11 @@
 
 import synth_common
 
+
+def to_s(ts):
+  return ts * 1000 * 1000 * 1000
+
+
 trace = synth_common.create_trace()
 trace.add_packet()
 trace.add_process(1, 0, 'init')
@@ -27,64 +32,80 @@
 
 # Start intent for a successful launch of calendar
 trace.add_atrace_begin(
-    ts=102, tid=2, pid=2, buf='MetricsLogger:launchObserverNotifyIntentStarted')
-trace.add_atrace_end(ts=103, tid=2, pid=2)
+    ts=to_s(102),
+    tid=2,
+    pid=2,
+    buf='MetricsLogger:launchObserverNotifyIntentStarted')
+trace.add_atrace_end(ts=to_s(103), tid=2, pid=2)
 
 trace.add_atrace_async_begin(
-    ts=110, tid=2, pid=2, buf='launching: com.google.android.calendar')
+    ts=to_s(110), tid=2, pid=2, buf='launching: com.google.android.calendar')
 
 trace.add_atrace_begin(
-    ts=120, tid=2, pid=2, buf='Start proc: com.google.android.calendar')
-trace.add_atrace_end(ts=155, tid=2, pid=2)
+    ts=to_s(120), tid=2, pid=2, buf='Start proc: com.google.android.calendar')
+trace.add_atrace_end(ts=to_s(155), tid=2, pid=2)
 
 # Unrelated process binding, ignored
-trace.add_atrace_begin(ts=125, tid=1, pid=1, buf='bindApplication')
-trace.add_atrace_end(ts=195, tid=1, pid=1)
+trace.add_atrace_begin(ts=to_s(125), tid=1, pid=1, buf='bindApplication')
+trace.add_atrace_end(ts=to_s(195), tid=1, pid=1)
 
-trace.add_atrace_begin(ts=185, tid=3, pid=3, buf='bindApplication')
+trace.add_atrace_begin(ts=to_s(185), tid=3, pid=3, buf='bindApplication')
 trace.add_atrace_begin(
-    ts=188,
+    ts=to_s(188),
     tid=3,
     pid=3,
     buf='performCreate:com.google.android.calendar.MainActivity')
-trace.add_atrace_begin(ts=188, tid=3, pid=3, buf='inflate')
-trace.add_atrace_end(ts=189, tid=3, pid=3)
+trace.add_atrace_begin(ts=to_s(188), tid=3, pid=3, buf='inflate')
+trace.add_atrace_end(ts=to_s(189), tid=3, pid=3)
 trace.add_atrace_begin(
-    ts=188, tid=3, pid=3, buf='ResourcesManager#getResources')
-trace.add_atrace_end(ts=189, tid=3, pid=3)
-trace.add_atrace_begin(ts=190, tid=3, pid=3, buf='inflate')
-trace.add_atrace_end(ts=192, tid=3, pid=3)
-trace.add_atrace_end(ts=192, tid=3, pid=3)
+    ts=to_s(188), tid=3, pid=3, buf='ResourcesManager#getResources')
+trace.add_atrace_end(ts=to_s(189), tid=3, pid=3)
+trace.add_atrace_begin(ts=to_s(190), tid=3, pid=3, buf='inflate')
+trace.add_atrace_end(ts=to_s(192), tid=3, pid=3)
+trace.add_atrace_end(ts=to_s(192), tid=3, pid=3)
 trace.add_atrace_begin(
     ts=193,
     tid=3,
     pid=3,
     buf='performResume:com.google.android.calendar.MainActivity')
-trace.add_atrace_end(ts=194, tid=3, pid=3)
-trace.add_atrace_end(ts=195, tid=3, pid=3)
+trace.add_atrace_end(ts=to_s(194), tid=3, pid=3)
+trace.add_atrace_end(ts=to_s(195), tid=3, pid=3)
 
 trace.add_atrace_begin(
-    ts=200,
+    ts=to_s(200),
     tid=3,
     pid=3,
     buf='location=error status=io-error-no-oat ' \
         'filter=run-from-apk reason=unknown')
-trace.add_atrace_end(ts=202, tid=3, pid=3)
+trace.add_atrace_end(ts=to_s(202), tid=3, pid=3)
 trace.add_atrace_begin(
-    ts=204,
+    ts=to_s(204),
     tid=3,
     pid=3,
     buf='location=/system/framework/oat/arm/com.android.location.provider' \
         '.odex status=up-to-date filter=speed reason=prebuilt')
-trace.add_atrace_end(ts=205, tid=3, pid=3)
+trace.add_atrace_end(ts=to_s(205), tid=3, pid=3)
 
 trace.add_atrace_async_end(
-    ts=210, tid=2, pid=2, buf='launching: com.google.android.calendar')
+    ts=to_s(210), tid=2, pid=2, buf='launching: com.google.android.calendar')
 trace.add_atrace_begin(
-    ts=211,
+    ts=to_s(211),
     tid=2,
     pid=2,
     buf='MetricsLogger:launchObserverNotifyActivityLaunchFinished')
-trace.add_atrace_end(ts=212, tid=2, pid=2)
+trace.add_atrace_end(ts=to_s(212), tid=2, pid=2)
+
+# Add the scheduling data to match the timestamps of events above but with
+# some idle time inbetween to make the computation more realisitic.
+trace.add_cpufreq(ts=to_s(50), freq=1000, cpu=0)
+trace.add_sched(ts=to_s(100), prev_pid=0, next_pid=2)
+trace.add_sched(ts=to_s(115), prev_pid=2, next_pid=0)
+trace.add_sched(ts=to_s(120), prev_pid=0, next_pid=2)
+trace.add_sched(ts=to_s(125), prev_pid=2, next_pid=1)
+trace.add_sched(ts=to_s(150), prev_pid=1, next_pid=2)
+trace.add_sched(ts=to_s(160), prev_pid=2, next_pid=1)
+trace.add_sched(ts=to_s(180), prev_pid=1, next_pid=3)
+trace.add_sched(ts=to_s(205), prev_pid=3, next_pid=2)
+trace.add_sched(ts=to_s(220), prev_pid=2, next_pid=0)
 
 sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/startup/android_startup_process_track.out b/test/trace_processor/startup/android_startup_process_track.out
index 3a3d5a8..817b19d 100644
--- a/test/trace_processor/startup/android_startup_process_track.out
+++ b/test/trace_processor/startup/android_startup_process_track.out
@@ -20,6 +20,8 @@
         dur_ns: 2
         dur_ms: 2e-06
       }
+      mcycles_by_core_type {
+      }
       dur_ms: 4e-06
     }
     activity_hosting_process_count: 1
@@ -45,6 +47,8 @@
         dur_ns: 2
         dur_ms: 2e-06
       }
+      mcycles_by_core_type {
+      }
       dur_ms: 4e-06
     }
     activity_hosting_process_count: 1