tp: Add support for pre 29 SDK startups.
Change-Id: Ic2b8efc8665e2afbbf8bc71720b58c7a58f59c57
diff --git a/Android.bp b/Android.bp
index 43d2027..40484c4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12380,6 +12380,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql",
"src/trace_processor/perfetto_sql/stdlib/android/frames/per_frame_metrics.sql",
"src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql",
"src/trace_processor/perfetto_sql/stdlib/android/freezer.sql",
"src/trace_processor/perfetto_sql/stdlib/android/garbage_collection.sql",
"src/trace_processor/perfetto_sql/stdlib/android/input.sql",
diff --git a/BUILD b/BUILD
index 2b53c16..4e316ed 100644
--- a/BUILD
+++ b/BUILD
@@ -2392,6 +2392,7 @@
srcs = [
"src/trace_processor/perfetto_sql/stdlib/android/frames/per_frame_metrics.sql",
"src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql",
],
)
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn
index bc434d5..306758a 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn
@@ -18,5 +18,6 @@
sources = [
"per_frame_metrics.sql",
"timeline.sql",
+ "timeline_maxsdk28.sql",
]
}
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql
index b492bb3..3d29281 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql
@@ -13,6 +13,9 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
+INCLUDE PERFETTO MODULE slices.with_context;
+INCLUDE PERFETTO MODULE android.frames.timeline_maxsdk28;
+
-- Parses the slice name to fetch `frame_id` from `slice` table.
-- Use with caution. Slice names are a flaky source of ids and the resulting
-- table might require some further operations.
@@ -23,13 +26,16 @@
-- `slice.id` of the frame slice.
id INT,
-- Parsed frame id.
- frame_id INT
+ frame_id INT,
+ -- Utid.
+ utid INT
) AS
WITH all_found AS (
SELECT
id,
- cast_int!(STR_SPLIT(name, ' ', 1)) AS frame_id
- FROM slice
+ cast_int!(STR_SPLIT(name, ' ', 1)) AS frame_id,
+ utid
+ FROM thread_slice
WHERE name GLOB $glob_str
)
SELECT *
@@ -47,11 +53,10 @@
ui_thread_utid INT
) AS
SELECT
- c.*,
- thread_track.utid AS ui_thread_utid
-FROM _get_frame_table_with_id('Choreographer#doFrame*') c
-JOIN slice USING (id)
-JOIN thread_track ON (thread_track.id = slice.track_id);
+ id,
+ frame_id,
+ utid AS ui_thread_utid
+FROM _get_frame_table_with_id('Choreographer#doFrame*');
-- All of the `DrawFrame` slices with their frame id and render thread.
-- There might be multiple DrawFrames slices for a single vsync (frame id).
@@ -66,11 +71,10 @@
render_thread_utid INT
) AS
SELECT
- d.*,
- thread_track.utid AS render_thread_utid
-FROM _get_frame_table_with_id('DrawFrame*') d
-JOIN slice USING (id)
-JOIN thread_track ON (thread_track.id = slice.track_id);
+ id,
+ frame_id,
+ utid AS render_thread_utid
+FROM _get_frame_table_with_id('DrawFrame*');
-- `actual_frame_timeline_slice` returns the same slice on different tracks.
-- We are getting the first slice with one frame id.
@@ -119,21 +123,47 @@
-- `utid` of the UI thread.
ui_thread_utid INT
) AS
+WITH frames_sdk_after_28 AS (
SELECT
frame_id,
ts,
dur,
do_frame.id AS do_frame_id,
draw_frame.id AS draw_frame_id,
- act.id AS actual_frame_timeline_id,
- exp.id AS expected_frame_timeline_id,
draw_frame.render_thread_utid,
- do_frame.ui_thread_utid
+ do_frame.ui_thread_utid,
+ "after_28" AS sdk,
+ act.id AS actual_frame_timeline_id,
+ exp.id AS expected_frame_timeline_id
FROM android_frames_choreographer_do_frame do_frame
JOIN android_frames_draw_frame draw_frame USING (frame_id)
JOIN _distinct_from_actual_timeline_slice act USING (frame_id)
JOIN _distinct_from_expected_timeline_slice exp USING (frame_id)
-ORDER BY frame_id;
+ORDER BY frame_id
+),
+all_frames AS (
+ SELECT * FROM frames_sdk_after_28
+ UNION
+ SELECT
+ *,
+ NULL AS actual_frame_timeline_id,
+ NULL AS expected_frame_timeline_id
+ FROM _frames_maxsdk_28
+)
+SELECT
+ frame_id,
+ ts,
+ dur,
+ do_frame_id,
+ draw_frame_id,
+ actual_frame_timeline_id,
+ expected_frame_timeline_id,
+ render_thread_utid,
+ ui_thread_utid
+FROM all_frames
+WHERE sdk = IIF(
+ (SELECT COUNT(1) FROM actual_frame_timeline_slice) > 0,
+ "after_28", "maxsdk28");
-- Returns first frame after the provided timestamp. The returning table has at
-- most one row.
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql
new file mode 100644
index 0000000..b8fad07
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql
@@ -0,0 +1,76 @@
+--
+-- Copyright 2024 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.
+
+INCLUDE PERFETTO MODULE slices.with_context;
+
+-- All slices related to one frame for max SDK 28. Aggregates
+-- "Choreographer#doFrame" and "DrawFrame". Tries to guess the `ts` and `dur`
+-- of the frame by first guessing which "DrawFrame" slices are related to which
+-- "Choreographer#doSlice".
+CREATE PERFETTO TABLE _frames_maxsdk_28(
+ -- Frame id. Created manually starting from 0.
+ frame_id INT,
+ -- Timestamp of the frame. Start of "Choreographer#doFrame" slice.
+ ts INT,
+ -- Duration of the frame, defined as the duration until the last
+ -- "DrawFrame" of this frame finishes.
+ dur INT,
+ -- `slice.id` of "Choreographer#doFrame" slice.
+ do_frame_id INT,
+ -- `slice.id` of "DrawFrame" slice. Fetched as one of the "DrawFrame"
+ -- slices that happen for the same process as "Choreographer#doFrame" slice
+ -- and start after it started and before the next "doFrame" started.
+ draw_frame_id INT,
+ -- `utid` of the render thread.
+ render_thread_utid INT,
+ -- `utid` of the UI thread.
+ ui_thread_utid INT,
+ -- "maxsdk28"
+ sdk STRING
+) AS
+WITH do_frames AS (
+ SELECT
+ id,
+ ts,
+ LEAD(ts, 1, TRACE_END()) OVER (PARTITION BY upid ORDER BY ts) AS next_do_frame,
+ utid,
+ upid
+ FROM thread_slice
+ WHERE name = 'Choreographer#doFrame' AND is_main_thread = 1
+ ORDER BY ts
+),
+draw_frames AS (
+ SELECT
+ id,
+ ts,
+ dur,
+ ts + dur AS ts_end,
+ utid,
+ upid
+ FROM thread_slice
+ WHERE name = 'DrawFrame'
+)
+SELECT
+ ROW_NUMBER() OVER () AS frame_id,
+ do.ts,
+ MAX(draw.ts_end) OVER (PARTITION BY do.id) - do.ts AS dur,
+ do.id AS do_frame_id,
+ draw.id AS draw_frame_id,
+ draw.utid AS render_thread_utid,
+ do.utid AS ui_thread_utid,
+ "maxsdk28" AS sdk
+FROM do_frames do
+JOIN draw_frames draw ON (do.upid = draw.upid AND draw.ts >= do.ts AND draw.ts < next_do_frame)
+ORDER BY do.ts;
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql b/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql
index 0a7fab2..5188b63 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql
@@ -13,17 +13,51 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
+INCLUDE PERFETTO MODULE slices.with_context;
INCLUDE PERFETTO MODULE android.startup.startup_events;
+INCLUDE PERFETTO MODULE android.frames.timeline;
CREATE PERFETTO TABLE _startups_maxsdk28 AS
+-- Warm and cold starts only are based on the launching slice
+WITH warm_and_cold AS (
+ SELECT
+ le.ts,
+ le.ts_end AS ts_end,
+ package_name AS package
+ FROM _startup_events le
+),
+-- Hot starts don’t have a launching slice so we use activityResume as a
+-- proxy.
+--
+-- Note that this implementation will also count warm and cold starts but
+-- we will remove those below.
+maybe_hot AS (
+ SELECT
+ sl.ts,
+ rs.ts + rs.dur AS ts_end,
+ -- We use the process name as the package as we have no better option.
+ process_name AS package
+ FROM thread_slice sl
+ JOIN android_first_frame_after(sl.ts) rs
+ WHERE name = 'activityResume'
+ -- Remove any launches here where the activityResume slices happens during
+ -- a warm/cold startup.
+ AND sl.ts NOT IN (SELECT ts FROM warm_and_cold)
+),
+cold_warm_hot AS (
+ SELECT * FROM warm_and_cold
+ UNION ALL
+ SELECT * FROM maybe_hot
+
+)
SELECT
- "maxsdk28" as sdk,
+ "maxsdk28" AS sdk,
ROW_NUMBER() OVER(ORDER BY ts) AS startup_id,
- le.ts,
- le.ts_end AS ts_end,
- le.ts_end - le.ts AS dur,
- package_name AS package,
+ ts,
+ ts_end,
+ ts_end - ts AS dur,
+ package,
NULL AS startup_type
-FROM _startup_events le
-ORDER BY ts;
+FROM cold_warm_hot;
+
diff --git a/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql b/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql
index 6e9ba0d..9430bd9 100644
--- a/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql
@@ -36,8 +36,10 @@
thread_name STRING,
-- Alias for `thread.utid`.
utid INT,
- -- Alias for `thread.tid`
+ -- Alias for `thread.tid`.
tid INT,
+ -- Alias for `thread.is_main_thread`.
+ is_main_thread BOOL,
-- Alias for `process.name`.
process_name STRING,
-- Alias for `process.upid`.
@@ -67,6 +69,7 @@
thread.name AS thread_name,
thread.utid,
thread.tid,
+ thread.is_main_thread,
process.name AS process_name,
process.upid,
process.pid,
diff --git a/test/data/api24_startup_cold.perfetto-trace.sha256 b/test/data/api24_startup_cold.perfetto-trace.sha256
new file mode 100644
index 0000000..dbc4e62
--- /dev/null
+++ b/test/data/api24_startup_cold.perfetto-trace.sha256
@@ -0,0 +1 @@
+ac006a3ec74fac70feb58c2cfad840c552af0ebd25f03bdfbf14d5f77148764b
\ No newline at end of file
diff --git a/test/data/api24_startup_hot.perfetto-trace.sha256 b/test/data/api24_startup_hot.perfetto-trace.sha256
new file mode 100644
index 0000000..6fa48c6
--- /dev/null
+++ b/test/data/api24_startup_hot.perfetto-trace.sha256
@@ -0,0 +1 @@
+0ec527c6392adf16e8580ba0fa3eaccf69eccba36c863377eca5c5618f00f3ea
\ No newline at end of file
diff --git a/test/data/api24_startup_warm.perfetto-trace.sha256 b/test/data/api24_startup_warm.perfetto-trace.sha256
new file mode 100644
index 0000000..04eca80
--- /dev/null
+++ b/test/data/api24_startup_warm.perfetto-trace.sha256
@@ -0,0 +1 @@
+59d1e84ddf6a492c10d7b6ecebf7b80813e6a0a2b3bef7d854d5ef3cf7210137
\ No newline at end of file
diff --git a/test/data/api31_startup_hot.perfetto-trace.sha256 b/test/data/api31_startup_hot.perfetto-trace.sha256
new file mode 100644
index 0000000..8cac597
--- /dev/null
+++ b/test/data/api31_startup_hot.perfetto-trace.sha256
@@ -0,0 +1 @@
+072802c0adf6968d0eb9c56fa13b33cad32f583398d019dc8a798981164333c5
\ No newline at end of file
diff --git a/test/data/api32_startup_warm.perfetto-trace.sha256 b/test/data/api32_startup_warm.perfetto-trace.sha256
new file mode 100644
index 0000000..f83dd34
--- /dev/null
+++ b/test/data/api32_startup_warm.perfetto-trace.sha256
@@ -0,0 +1 @@
+776122b5660c5d6e738950031fdb4992a64e3224e9e82bbaed474a0a281ed7e3
\ No newline at end of file
diff --git a/test/data/api34_startup_cold.perfetto-trace.sha256 b/test/data/api34_startup_cold.perfetto-trace.sha256
new file mode 100644
index 0000000..2a7a044
--- /dev/null
+++ b/test/data/api34_startup_cold.perfetto-trace.sha256
@@ -0,0 +1 @@
+1958521dc5128cd4eadd1df281e19987aded718750e6883f82ffd3b5eb529bd6
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index 1f711b8..cb82c55 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -92,6 +92,7 @@
from diff_tests.parser.translated_args.tests import TranslatedArgs
from diff_tests.parser.ufs.tests import Ufs
from diff_tests.stdlib.android.frames_tests import Frames
+from diff_tests.stdlib.android.startups_tests import Startups
from diff_tests.stdlib.android.tests import AndroidStdlib
from diff_tests.stdlib.chrome.chrome_stdlib_testsuites import CHROME_STDLIB_TESTSUITES
from diff_tests.stdlib.common.tests import StdlibCommon
@@ -282,6 +283,7 @@
'StdlibIntervals').fetch(),
*IntervalsIntersect(index_path, 'stdlib/intervals',
'StdlibIntervalsIntersect').fetch(),
+ *Startups(index_path, 'stdlib/android', 'Startups').fetch(),
*Timestamps(index_path, 'stdlib/timestamps', 'Timestamps').fetch(),
*WattsonStdlib(index_path, 'stdlib/wattson', 'WattsonStdlib').fetch(),
] + chrome_stdlib_tests
diff --git a/test/trace_processor/diff_tests/stdlib/android/startups_tests.py b/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
new file mode 100644
index 0000000..14d002a
--- /dev/null
+++ b/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# Copyright (C) 2024 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 a
+#
+# http://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.
+
+from python.generators.diff_tests.testing import Path, DataPath
+from python.generators.diff_tests.testing import Csv, TextProto
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class Startups(TestSuite):
+
+ def test_hot_startups(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api31_startup_hot.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,186969441973689,186969489302704,47329015,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_warm_startups(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api32_startup_warm.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 28,157479786566030,157479943081777,156515747,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_cold_startups(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api34_startup_cold.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 61,17806781251694,17806891032171,109780477,"com.android.systemui.people","warm"
+ """))
+
+ def test_hot_startups_maxsdk28(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api24_startup_hot.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,779860286416,779893485322,33198906,"com.google.android.googlequicksearchbox","[NULL]"
+ 2,780778904571,780813944498,35039927,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_warm_startups_maxsdk28(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api24_startup_warm.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,799979565075,800014194731,34629656,"com.google.android.googlequicksearchbox","[NULL]"
+ 2,800868511677,800981929562,113417885,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_cold_startups_maxsdk28(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api24_startup_cold.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,791231114368,791501060868,269946500,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))