Merge "tp: backport startup metric for cold/warm starts to API 23" am: 39062645f9

Original change: https://android-review.googlesource.com/c/platform/external/perfetto/+/1878514

Change-Id: I6c9fc3817a5cfd8c6b95b73dba2b21f4175a6b25
diff --git a/Android.bp b/Android.bp
index 372249e..c7f2447 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8116,6 +8116,8 @@
         "src/trace_processor/metrics/sql/android/span_view_stats.sql",
         "src/trace_processor/metrics/sql/android/startup/hsc.sql",
         "src/trace_processor/metrics/sql/android/startup/launches.sql",
+        "src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql",
+        "src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql",
         "src/trace_processor/metrics/sql/android/thread_counter_span_view.sql",
         "src/trace_processor/metrics/sql/android/unsymbolized_frames.sql",
         "src/trace_processor/metrics/sql/chrome/actual_power_by_category.sql",
diff --git a/BUILD b/BUILD
index 94521a4..ccc51d8 100644
--- a/BUILD
+++ b/BUILD
@@ -1088,6 +1088,8 @@
         "src/trace_processor/metrics/sql/android/span_view_stats.sql",
         "src/trace_processor/metrics/sql/android/startup/hsc.sql",
         "src/trace_processor/metrics/sql/android/startup/launches.sql",
+        "src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql",
+        "src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql",
         "src/trace_processor/metrics/sql/android/thread_counter_span_view.sql",
         "src/trace_processor/metrics/sql/android/unsymbolized_frames.sql",
         "src/trace_processor/metrics/sql/chrome/actual_power_by_category.sql",
diff --git a/src/trace_processor/metrics/metrics.cc b/src/trace_processor/metrics/metrics.cc
index 6926cff..6c2536e 100644
--- a/src/trace_processor/metrics/metrics.cc
+++ b/src/trace_processor/metrics/metrics.cc
@@ -620,8 +620,9 @@
   auto metric_it = std::find_if(
       ctx->metrics->begin(), ctx->metrics->end(),
       [path](const SqlMetricFile& metric) { return metric.path == path; });
-  if (metric_it == ctx->metrics->end())
-    return base::ErrStatus("RUN_METRIC: Unknown filename provided");
+  if (metric_it == ctx->metrics->end()) {
+    return base::ErrStatus("RUN_METRIC: Unknown filename provided %s", path);
+  }
   const auto& sql = metric_it->sql;
 
   std::unordered_map<std::string, std::string> substitutions;
diff --git a/src/trace_processor/metrics/sql/BUILD.gn b/src/trace_processor/metrics/sql/BUILD.gn
index 064630b..7ddbf2a 100644
--- a/src/trace_processor/metrics/sql/BUILD.gn
+++ b/src/trace_processor/metrics/sql/BUILD.gn
@@ -71,6 +71,8 @@
   "android/gpu_counter_span_view.sql",
   "android/thread_counter_span_view.sql",
   "android/unsymbolized_frames.sql",
+  "android/startup/launches_maxsdk28.sql",
+  "android/startup/launches_minsdk29.sql",
   "android/startup/launches.sql",
   "android/startup/hsc.sql",
   "chrome/actual_power_by_category.sql",
diff --git a/src/trace_processor/metrics/sql/android/startup/launches.sql b/src/trace_processor/metrics/sql/android/startup/launches.sql
index c3be64c..4993cd5 100644
--- a/src/trace_processor/metrics/sql/android/startup/launches.sql
+++ b/src/trace_processor/metrics/sql/android/startup/launches.sql
@@ -12,29 +12,6 @@
 -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 -- See the License for the specific language governing permissions and
 -- limitations under the License.
---
-
--- Marks the beginning of the trace and is equivalent to when the statsd launch
--- logging begins.
-DROP VIEW IF EXISTS activity_intent_received;
-CREATE VIEW activity_intent_received AS
-SELECT ts FROM slice
-WHERE name = 'MetricsLogger:launchObserverNotifyIntentStarted';
-
--- We partition the trace into spans based on posted activity intents.
--- We will refine these progressively in the next steps to only encompass
--- activity starts.
-DROP TABLE IF EXISTS activity_intent_recv_spans;
-CREATE TABLE activity_intent_recv_spans(id INT, ts BIG INT, dur BIG INT);
-
-INSERT INTO activity_intent_recv_spans
-SELECT
-  ROW_NUMBER()
-    OVER(ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS id,
-  ts,
-  LEAD(ts, 1, (SELECT end_ts FROM trace_bounds)) OVER(ORDER BY ts) - ts AS dur
-FROM activity_intent_received
-ORDER BY ts;
 
 -- The start of the launching event corresponds to the end of the AM handling
 -- the startActivity intent, whereas the end corresponds to the first frame drawn.
@@ -52,50 +29,28 @@
 WHERE s.name GLOB 'launching: *'
 AND (process.name IS NULL OR process.name = 'system_server');
 
--- Filter activity_intent_recv_spans, keeping only the ones that triggered
--- a launch.
-DROP VIEW IF EXISTS launch_partitions;
-CREATE VIEW launch_partitions AS
-SELECT * FROM activity_intent_recv_spans AS spans
-WHERE 1 = (
-  SELECT COUNT(1)
-  FROM launching_events
-  WHERE launching_events.ts BETWEEN spans.ts AND spans.ts + spans.dur);
+SELECT CREATE_FUNCTION(
+  'ANDROID_SDK_LEVEL()',
+  'INT', "
+    SELECT int_value
+    FROM metadata
+    WHERE name = 'android_sdk_version'
+  ");
 
--- Successful activity launch. The end of the 'launching' event is not related
--- to whether it actually succeeded or not.
-DROP VIEW IF EXISTS activity_intent_launch_successful;
-CREATE VIEW activity_intent_launch_successful AS
-SELECT ts FROM slice
-WHERE name = 'MetricsLogger:launchObserverNotifyActivityLaunchFinished';
-
--- All activity launches in the trace, keyed by ID.
-DROP TABLE IF EXISTS launches;
-CREATE TABLE launches(
-  ts BIG INT,
-  ts_end BIG INT,
-  dur BIG INT,
-  id INT,
-  package STRING);
-
--- Use the starting event package name. The finish event package name
--- is not reliable in the case of failed launches.
-INSERT INTO launches
-SELECT
-  lpart.ts AS ts,
-  launching_events.ts_end AS ts_end,
-  launching_events.ts_end - lpart.ts AS dur,
-  lpart.id AS id,
-  package_name AS package
-FROM launch_partitions AS lpart
-JOIN launching_events ON
-  (launching_events.ts BETWEEN lpart.ts AND lpart.ts + lpart.dur) AND
-  (launching_events.ts_end BETWEEN lpart.ts AND lpart.ts + lpart.dur)
-WHERE (
-  SELECT COUNT(1)
-  FROM activity_intent_launch_successful AS successful
-  WHERE successful.ts BETWEEN lpart.ts AND lpart.ts + lpart.dur
-) > 0;
+-- Note: on Q, we didn't have Android fingerprints but we *did*
+-- have ActivityMetricsLogger events so we will use this approach
+-- if we see any such events.
+SELECT CASE
+  WHEN (
+    ANDROID_SDK_LEVEL() >= 29
+    OR (
+      SELECT COUNT(1) FROM slice
+      WHERE name GLOB 'MetricsLogger:*'
+    ) > 0
+  )
+  THEN RUN_METRIC('android/startup/launches_minsdk29.sql')
+  ELSE RUN_METRIC('android/startup/launches_maxsdk28.sql')
+END;
 
 -- Maps a launch to the corresponding set of processes that handled the
 -- activity start. The vast majority of cases should be a single process.
@@ -107,9 +62,17 @@
 INSERT INTO launch_processes
 SELECT launches.id, process.upid
 FROM launches
-  LEFT JOIN package_list ON (launches.package = package_list.package_name)
-  JOIN process ON (launches.package = process.name OR process.uid = package_list.uid)
-  JOIN thread ON (process.upid = thread.upid AND process.pid = thread.tid)
+LEFT JOIN package_list ON (
+  launches.package = package_list.package_name
+)
+JOIN process ON (
+  launches.package = process.name OR
+  process.uid = package_list.uid
+)
+JOIN thread ON (
+  process.upid = thread.upid AND
+  process.pid = thread.tid
+)
 WHERE (process.start_ts IS NULL OR process.start_ts < launches.ts_end)
 AND (thread.end_ts IS NULL OR thread.end_ts > launches.ts_end)
 ORDER BY process.start_ts DESC;
diff --git a/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql b/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql
new file mode 100644
index 0000000..8753da1
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/startup/launches_maxsdk28.sql
@@ -0,0 +1,36 @@
+--
+-- Copyright 2021 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- All activity launches in the trace, keyed by ID.
+DROP TABLE IF EXISTS launches;
+CREATE TABLE launches(
+  id INTEGER PRIMARY KEY,
+  ts BIG INT,
+  ts_end BIG INT,
+  dur BIG INT,
+  package STRING
+);
+
+-- Cold/warm starts emitted launching slices on API level 28-.
+INSERT INTO launches(ts, ts_end, dur, package)
+SELECT
+  launching_events.ts AS ts,
+  launching_events.ts_end AS ts_end,
+  launching_events.ts_end - launching_events.ts AS dur,
+  package_name AS package
+FROM launching_events;
+
+-- TODO(lalitm): add handling of hot starts using frame timings.
diff --git a/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql b/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql
new file mode 100644
index 0000000..1f4c0f7
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/startup/launches_minsdk29.sql
@@ -0,0 +1,82 @@
+--
+-- Copyright 2021 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Marks the beginning of the trace and is equivalent to when the statsd launch
+-- logging begins.
+DROP VIEW IF EXISTS activity_intent_received;
+CREATE VIEW activity_intent_received AS
+SELECT ts FROM slice
+WHERE name = 'MetricsLogger:launchObserverNotifyIntentStarted';
+
+-- We partition the trace into spans based on posted activity intents.
+-- We will refine these progressively in the next steps to only encompass
+-- activity starts.
+DROP TABLE IF EXISTS activity_intent_recv_spans;
+CREATE TABLE activity_intent_recv_spans(id INT, ts BIG INT, dur BIG INT);
+
+INSERT INTO activity_intent_recv_spans
+SELECT
+  ROW_NUMBER()
+    OVER(ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS id,
+  ts,
+  LEAD(ts, 1, (SELECT end_ts FROM trace_bounds)) OVER(ORDER BY ts) - ts AS dur
+FROM activity_intent_received
+ORDER BY ts;
+
+-- Filter activity_intent_recv_spans, keeping only the ones that triggered
+-- a launch.
+DROP VIEW IF EXISTS launch_partitions;
+CREATE VIEW launch_partitions AS
+SELECT * FROM activity_intent_recv_spans AS spans
+WHERE 1 = (
+  SELECT COUNT(1)
+  FROM launching_events
+  WHERE launching_events.ts BETWEEN spans.ts AND spans.ts + spans.dur);
+
+-- Successful activity launch. The end of the 'launching' event is not related
+-- to whether it actually succeeded or not.
+DROP VIEW IF EXISTS activity_intent_launch_successful;
+CREATE VIEW activity_intent_launch_successful AS
+SELECT ts FROM slice
+WHERE name = 'MetricsLogger:launchObserverNotifyActivityLaunchFinished';
+
+-- All activity launches in the trace, keyed by ID.
+DROP TABLE IF EXISTS launches;
+CREATE TABLE launches(
+  ts BIG INT,
+  ts_end BIG INT,
+  dur BIG INT,
+  id INT,
+  package STRING);
+
+-- Use the starting event package name. The finish event package name
+-- is not reliable in the case of failed launches.
+INSERT INTO launches
+SELECT
+  lpart.ts AS ts,
+  launching_events.ts_end AS ts_end,
+  launching_events.ts_end - lpart.ts AS dur,
+  lpart.id AS id,
+  package_name AS package
+FROM launch_partitions AS lpart
+JOIN launching_events ON
+  (launching_events.ts BETWEEN lpart.ts AND lpart.ts + lpart.dur) AND
+  (launching_events.ts_end BETWEEN lpart.ts AND lpart.ts + lpart.dur)
+WHERE (
+  SELECT COUNT(1)
+  FROM activity_intent_launch_successful AS successful
+  WHERE successful.ts BETWEEN lpart.ts AND lpart.ts + lpart.dur
+) > 0;
diff --git a/tools/gen_amalgamated_sql_metrics.py b/tools/gen_amalgamated_sql_metrics.py
index eed5d8e..16f6aac 100755
--- a/tools/gen_amalgamated_sql_metrics.py
+++ b/tools/gen_amalgamated_sql_metrics.py
@@ -85,7 +85,7 @@
     with open(file_name, 'r') as f:
       relpath = os.path.relpath(file_name, root_path)
       sql_outputs[relpath] = "".join(
-          x for x in f.readlines() if not x.startswith('--'))
+          x.lstrip() for x in f.readlines() if not x.lstrip().startswith('--'))
 
   with open(args.cpp_out, 'w+') as output:
     output.write(REPLACEMENT_HEADER)