| -- |
| -- Copyright 2019 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. |
| |
| SELECT IMPORT('common.slices'); |
| SELECT IMPORT('android.process_metadata'); |
| |
| -- All activity startup events. |
| CREATE TABLE internal_startup_events AS |
| SELECT |
| ts, |
| dur, |
| ts + dur AS ts_end, |
| STR_SPLIT(s.name, ": ", 1) AS package_name |
| FROM slice s |
| JOIN process_track t ON s.track_id = t.id |
| JOIN process USING(upid) |
| WHERE |
| s.name GLOB 'launching: *' |
| AND (process.name IS NULL OR process.name = 'system_server'); |
| |
| -- Gather all startup data. Populate by different sdks. |
| CREATE TABLE internal_all_startups( |
| sdk STRING, |
| startup_id INTEGER BIGINT, |
| ts BIGINT, |
| ts_end BIGINT, |
| dur BIGINT, |
| package STRING, |
| startup_type STRING |
| ); |
| |
| SELECT IMPORT('android.startup.internal_startups_maxsdk28'); |
| SELECT IMPORT('android.startup.internal_startups_minsdk29'); |
| SELECT IMPORT('android.startup.internal_startups_minsdk33'); |
| |
| -- All activity startups in the trace by startup id. |
| -- Populated by different scripts depending on the platform version/contents. |
| -- |
| -- @column id Startup id. |
| -- @column ts Timestamp of startup start. |
| -- @column ts_end Timestamp of startup end. |
| -- @column dur Startup duration. |
| -- @column package Package name. |
| -- @column startup_type Startup type. |
| CREATE TABLE android_startups AS |
| SELECT startup_id, ts, ts_end, dur, package, startup_type FROM |
| internal_all_startups WHERE ( CASE |
| WHEN SLICE_COUNT('launchingActivity#*:*') > 0 |
| THEN sdk = "minsdk33" |
| WHEN SLICE_COUNT('MetricsLogger:*') > 0 |
| THEN sdk = "minsdk29" |
| ELSE sdk = "maxsdk28" |
| END); |
| |
| -- |
| -- Create startup processes |
| -- |
| |
| -- Create a table containing only the slices which are necessary for determining |
| -- whether a startup happened. |
| CREATE TABLE internal_startup_indicator_slices AS |
| SELECT ts, name, track_id |
| FROM slice |
| WHERE name IN ('bindApplication', 'activityStart', 'activityResume'); |
| |
| SELECT CREATE_FUNCTION( |
| 'INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(start_ts LONG, end_ts LONG, utid INT, name STRING)', |
| 'INT', |
| ' |
| SELECT COUNT(1) |
| FROM thread_track t |
| JOIN internal_startup_indicator_slices s ON s.track_id = t.id |
| WHERE |
| t.utid = $utid AND |
| s.ts >= $start_ts AND |
| s.ts < $end_ts AND |
| s.name = $name |
| ' |
| ); |
| |
| -- Maps a startup to the set of processes that handled the activity start. |
| -- |
| -- The vast majority of cases should be a single process. However it is |
| -- possible that the process dies during the activity startup and is respawned. |
| -- |
| -- @column startup_id Startup id. |
| -- @column upid Upid of process on which activity started. |
| -- @column startup_type Type of the startup. |
| CREATE TABLE android_startup_processes AS |
| -- This is intentionally a materialized query. For some reason, if we don't |
| -- materialize, we end up with a query which is an order of magnitude slower :( |
| WITH startup_with_type AS MATERIALIZED ( |
| SELECT |
| startup_id, |
| upid, |
| CASE |
| -- type parsed from platform event takes precedence if available |
| WHEN startup_type IS NOT NULL THEN startup_type |
| WHEN bind_app > 0 AND a_start > 0 AND a_resume > 0 THEN 'cold' |
| WHEN a_start > 0 AND a_resume > 0 THEN 'warm' |
| WHEN a_resume > 0 THEN 'hot' |
| ELSE NULL |
| END AS startup_type |
| FROM ( |
| SELECT |
| l.startup_id, |
| l.startup_type, |
| p.upid, |
| INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(l.ts, l.ts_end, t.utid, 'bindApplication') AS bind_app, |
| INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(l.ts, l.ts_end, t.utid, 'activityStart') AS a_start, |
| INTERNAL_STARTUP_INDICATOR_SLICE_COUNT(l.ts, l.ts_end, t.utid, 'activityResume') AS a_resume |
| FROM android_startups l |
| JOIN android_process_metadata p ON ( |
| l.package = p.package_name |
| -- If the package list data source was not enabled in the trace, nothing |
| -- will match the above constraint so also match any process whose name |
| -- is a prefix of the package name. |
| OR ( |
| (SELECT COUNT(1) = 0 FROM package_list) |
| AND p.process_name GLOB l.package || '*' |
| ) |
| ) |
| JOIN thread t ON (p.upid = t.upid AND t.is_main_thread) |
| ) |
| ) |
| SELECT * |
| FROM startup_with_type |
| WHERE startup_type IS NOT NULL; |
| |
| |
| -- Maps a startup to the set of threads on processes that handled the |
| -- activity start. |
| -- |
| -- @column startup_id Startup id. |
| -- @column ts Timestamp of start. |
| -- @column dur Duration of startup. |
| -- @column upid Upid of process involved in startup. |
| -- @column utid Utid of the thread. |
| -- @column thread_name Name of the thread. |
| -- @column is_main_thread Thread is a main thread. |
| CREATE VIEW android_startup_threads AS |
| SELECT |
| startups.startup_id, |
| startups.ts, |
| startups.dur, |
| android_startup_processes.upid, |
| thread.utid, |
| thread.name AS thread_name, |
| thread.is_main_thread AS is_main_thread |
| FROM android_startups startups |
| JOIN android_startup_processes USING (startup_id) |
| JOIN thread USING (upid); |
| |
| --- |
| --- Functions |
| --- |
| |
| -- All the slices for all startups in trace. |
| -- |
| -- Generally, this view should not be used. Instead, use one of the view functions related |
| -- to the startup slices which are created from this table. |
| -- |
| -- @column startup_ts Timestamp of startup. |
| -- @column startup_ts_end Timestamp of startup end. |
| -- @column startup_id Startup id. |
| -- @column utid UTID of thread with slice. |
| -- @column thread_name Name of thread. |
| -- @column is_main_thread Whether it is main thread. |
| -- @column arg_set_id Arg set id. |
| -- @column slice_id Slice id. |
| -- @column slice_name Name of slice. |
| -- @column slice_ts Timestamp of slice start. |
| -- @column slice_dur Slice duration. |
| CREATE VIEW android_thread_slices_for_all_startups AS |
| SELECT |
| st.ts AS startup_ts, |
| st.ts + st.dur AS startup_ts_end, |
| st.startup_id, |
| st.utid, |
| st.thread_name, |
| st.is_main_thread, |
| slice.arg_set_id, |
| slice.id as slice_id, |
| slice.name AS slice_name, |
| slice.ts AS slice_ts, |
| slice.dur AS slice_dur |
| FROM android_startup_threads st |
| JOIN thread_track USING (utid) |
| JOIN slice ON (slice.track_id = thread_track.id) |
| WHERE slice.ts BETWEEN st.ts AND st.ts + st.dur; |
| |
| -- Given a startup id and GLOB for a slice name, returns matching slices with data. |
| -- |
| -- @arg startup_id INT Startup id. |
| -- @arg slice_name STRING Glob of the slice. |
| -- @column slice_name Name of the slice. |
| -- @column slice_ts Timestamp of start of the slice. |
| -- @column slice_dur Duration of the slice. |
| -- @column thread_name Name of the thread with the slice. |
| -- @column arg_set_id Arg set id. |
| SELECT CREATE_VIEW_FUNCTION( |
| 'ANDROID_SLICES_FOR_STARTUP_AND_SLICE_NAME(startup_id INT, slice_name STRING)', |
| 'slice_name STRING, slice_ts INT, slice_dur INT, thread_name STRING, arg_set_id INT', |
| ' |
| SELECT slice_name, slice_ts, slice_dur, thread_name, arg_set_id |
| FROM android_thread_slices_for_all_startups |
| WHERE startup_id = $startup_id AND slice_name GLOB $slice_name |
| ' |
| ); |
| |
| -- Returns binder transaction slices for a given startup id with duration over threshold. |
| -- |
| -- @arg startup_id INT Startup id. |
| -- @arg threshold DOUBLE Only return slices with duration over threshold. |
| -- @column id Slice id. |
| -- @column slice_dur Slice duration. |
| -- @column thread_name Name of the thread with slice. |
| -- @column process Name of the process with slice. |
| -- @column arg_set_id Arg set id. |
| -- @column is_main_thread Whether is main thread. |
| SELECT CREATE_VIEW_FUNCTION( |
| 'ANDROID_BINDER_TRANSACTION_SLICES_FOR_STARTUP(startup_id INT, threshold DOUBLE)', |
| 'id INT, slice_dur INT, thread_name STRING, process STRING, arg_set_id INT, is_main_thread BOOL', |
| ' |
| SELECT slice_id as id, slice_dur, thread_name, process.name as process, s.arg_set_id, is_main_thread |
| FROM android_thread_slices_for_all_startups s |
| JOIN process ON ( |
| EXTRACT_ARG(s.arg_set_id, "destination process") = process.pid |
| ) |
| WHERE startup_id = $startup_id AND slice_name GLOB "binder transaction" AND slice_dur > $threshold |
| ' |
| ); |
| |
| -- Returns duration of startup for slice name. |
| -- |
| -- Sums duration of all slices of startup with provided name. |
| -- |
| -- @arg startup_id LONG Startup id. |
| -- @arg slice_name STRING Slice name. |
| -- @ret INT Sum of duration. |
| SELECT CREATE_FUNCTION( |
| 'ANDROID_SUM_DUR_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)', |
| 'INT', |
| ' |
| SELECT SUM(slice_dur) |
| FROM android_thread_slices_for_all_startups |
| WHERE startup_id = $startup_id AND slice_name GLOB $slice_name |
| ' |
| ); |
| |
| -- Returns duration of startup for slice name on main thread. |
| -- |
| -- Sums duration of all slices of startup with provided name only on main thread. |
| -- |
| -- @arg startup_id LONG Startup id. |
| -- @arg slice_name STRING Slice name. |
| -- @ret INT Sum of duration. |
| SELECT CREATE_FUNCTION( |
| 'ANDROID_SUM_DUR_ON_MAIN_THREAD_FOR_STARTUP_AND_SLICE(startup_id LONG, slice_name STRING)', |
| 'INT', |
| ' |
| SELECT SUM(slice_dur) |
| FROM android_thread_slices_for_all_startups |
| WHERE startup_id = $startup_id AND slice_name GLOB $slice_name AND is_main_thread |
| ' |
| ); |