1-- 2-- Copyright 2019 The Android Open Source Project 3-- 4-- Licensed under the Apache License, Version 2.0 (the "License"); 5-- you may not use this file except in compliance with the License. 6-- You may obtain a copy of the License at 7-- 8-- https://www.apache.org/licenses/LICENSE-2.0 9-- 10-- Unless required by applicable law or agreed to in writing, software 11-- distributed under the License is distributed on an "AS IS" BASIS, 12-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13-- See the License for the specific language governing permissions and 14-- limitations under the License. 15 16INCLUDE PERFETTO MODULE android.process_metadata; 17INCLUDE PERFETTO MODULE android.startup.startups_maxsdk28; 18INCLUDE PERFETTO MODULE android.startup.startups_minsdk29; 19INCLUDE PERFETTO MODULE android.startup.startups_minsdk33; 20 21CREATE PERFETTO FUNCTION _slice_count( 22 -- Name of the slices to counted. 23 slice_glob STRING) 24-- Number of slices with the name. 25RETURNS INT AS 26SELECT COUNT(1) FROM slice WHERE name GLOB $slice_glob; 27 28-- Gather all startup data. Populate by different sdks. 29CREATE PERFETTO TABLE _all_startups AS 30SELECT sdk, startup_id, ts, ts_end, dur, package, startup_type FROM _startups_maxsdk28 31UNION ALL 32SELECT sdk, startup_id, ts, ts_end, dur, package, startup_type FROM _startups_minsdk29 33UNION ALL 34SELECT sdk, startup_id, ts, ts_end, dur, package, startup_type FROM _startups_minsdk33; 35 36-- All activity startups in the trace by startup id. 37-- Populated by different scripts depending on the platform version/contents. 38CREATE PERFETTO TABLE android_startups( 39 -- Startup id. 40 startup_id INT, 41 -- Timestamp of startup start. 42 ts INT, 43 -- Timestamp of startup end. 44 ts_end INT, 45 -- Startup duration. 46 dur INT, 47 -- Package name. 48 package STRING, 49 -- Startup type. 50 startup_type STRING 51) AS 52SELECT startup_id, ts, ts_end, dur, package, startup_type FROM 53_all_startups WHERE ( CASE 54 WHEN _slice_count('launchingActivity#*:*') > 0 55 THEN sdk = "minsdk33" 56 WHEN _slice_count('MetricsLogger:*') > 0 57 THEN sdk = "minsdk29" 58 ELSE sdk = "maxsdk28" 59 END); 60 61-- Create a table containing only the slices which are necessary for determining 62-- whether a startup happened. 63CREATE PERFETTO TABLE _startup_indicator_slices AS 64SELECT ts, name, track_id 65FROM slice 66WHERE name IN ('bindApplication', 'activityStart', 'activityResume'); 67 68CREATE PERFETTO FUNCTION _startup_indicator_slice_count(start_ts LONG, 69 end_ts LONG, 70 utid INT, 71 name STRING) 72RETURNS INT AS 73SELECT COUNT(1) 74FROM thread_track t 75JOIN _startup_indicator_slices s ON s.track_id = t.id 76WHERE 77 t.utid = $utid AND 78 s.ts >= $start_ts AND 79 s.ts < $end_ts AND 80 s.name = $name; 81 82-- Maps a startup to the set of processes that handled the activity start. 83-- 84-- The vast majority of cases should be a single process. However it is 85-- possible that the process dies during the activity startup and is respawned. 86CREATE PERFETTO TABLE android_startup_processes( 87 -- Startup id. 88 startup_id INT, 89 -- Upid of process on which activity started. 90 upid INT, 91 -- Type of the startup. 92 startup_type INT 93) AS 94-- This is intentionally a materialized query. For some reason, if we don't 95-- materialize, we end up with a query which is an order of magnitude slower :( 96WITH startup_with_type AS MATERIALIZED ( 97 SELECT 98 startup_id, 99 upid, 100 CASE 101 -- type parsed from platform event takes precedence if available 102 WHEN startup_type IS NOT NULL THEN startup_type 103 WHEN bind_app > 0 AND a_start > 0 AND a_resume > 0 THEN 'cold' 104 WHEN a_start > 0 AND a_resume > 0 THEN 'warm' 105 WHEN a_resume > 0 THEN 'hot' 106 ELSE NULL 107 END AS startup_type 108 FROM ( 109 SELECT 110 l.startup_id, 111 l.startup_type, 112 p.upid, 113 _startup_indicator_slice_count(l.ts, l.ts_end, t.utid, 'bindApplication') AS bind_app, 114 _startup_indicator_slice_count(l.ts, l.ts_end, t.utid, 'activityStart') AS a_start, 115 _startup_indicator_slice_count(l.ts, l.ts_end, t.utid, 'activityResume') AS a_resume 116 FROM android_startups l 117 JOIN android_process_metadata p ON ( 118 l.package = p.package_name 119 -- If the package list data source was not enabled in the trace, nothing 120 -- will match the above constraint so also match any process whose name 121 -- is a prefix of the package name. 122 OR ( 123 (SELECT COUNT(1) = 0 FROM package_list) 124 AND p.process_name GLOB l.package || '*' 125 ) 126 ) 127 JOIN thread t ON (p.upid = t.upid AND t.is_main_thread) 128 -- Filter out the non-startup processes with the same package name as that of a startup. 129 WHERE a_resume > 0 130 ) 131) 132SELECT * 133FROM startup_with_type 134WHERE startup_type IS NOT NULL; 135 136 137-- Maps a startup to the set of threads on processes that handled the 138-- activity start. 139CREATE PERFETTO VIEW android_startup_threads( 140 -- Startup id. 141 startup_id INT, 142 -- Timestamp of start. 143 ts INT, 144 -- Duration of startup. 145 dur INT, 146 -- Upid of process involved in startup. 147 upid INT, 148 -- Utid of the thread. 149 utid INT, 150 -- Name of the thread. 151 thread_name STRING, 152 -- Thread is a main thread. 153 is_main_thread BOOL 154) AS 155SELECT 156 startups.startup_id, 157 startups.ts, 158 startups.dur, 159 android_startup_processes.upid, 160 thread.utid, 161 thread.name AS thread_name, 162 thread.is_main_thread AS is_main_thread 163FROM android_startups startups 164JOIN android_startup_processes USING (startup_id) 165JOIN thread USING (upid); 166 167--- 168--- Functions 169--- 170 171-- All the slices for all startups in trace. 172-- 173-- Generally, this view should not be used. Instead, use one of the view functions related 174-- to the startup slices which are created from this table. 175CREATE PERFETTO VIEW android_thread_slices_for_all_startups( 176 -- Timestamp of startup. 177 startup_ts INT, 178 -- Timestamp of startup end. 179 startup_ts_end INT, 180 -- Startup id. 181 startup_id INT, 182 -- UTID of thread with slice. 183 utid INT, 184 -- Name of thread. 185 thread_name STRING, 186 -- Whether it is main thread. 187 is_main_thread BOOL, 188 -- Arg set id. 189 arg_set_id INT, 190 -- Slice id. 191 slice_id INT, 192 -- Name of slice. 193 slice_name STRING, 194 -- Timestamp of slice start. 195 slice_ts INT, 196 -- Slice duration. 197 slice_dur INT 198) AS 199SELECT 200 st.ts AS startup_ts, 201 st.ts + st.dur AS startup_ts_end, 202 st.startup_id, 203 st.utid, 204 st.thread_name, 205 st.is_main_thread, 206 slice.arg_set_id, 207 slice.id as slice_id, 208 slice.name AS slice_name, 209 slice.ts AS slice_ts, 210 slice.dur AS slice_dur 211FROM android_startup_threads st 212JOIN thread_track USING (utid) 213JOIN slice ON (slice.track_id = thread_track.id) 214WHERE slice.ts BETWEEN st.ts AND st.ts + st.dur; 215 216-- Given a startup id and GLOB for a slice name, returns matching slices with data. 217CREATE PERFETTO FUNCTION android_slices_for_startup_and_slice_name( 218 -- Startup id. 219 startup_id INT, 220 -- Glob of the slice. 221 slice_name STRING) 222RETURNS TABLE( 223 -- Id of the slice. 224 slice_id INT, 225 -- Name of the slice. 226 slice_name STRING, 227 -- Timestamp of start of the slice. 228 slice_ts INT, 229 -- Duration of the slice. 230 slice_dur INT, 231 -- Name of the thread with the slice. 232 thread_name STRING, 233 -- Arg set id. 234 arg_set_id INT 235) AS 236SELECT slice_id, slice_name, slice_ts, slice_dur, thread_name, arg_set_id 237FROM android_thread_slices_for_all_startups 238WHERE startup_id = $startup_id AND slice_name GLOB $slice_name; 239 240-- Returns binder transaction slices for a given startup id with duration over threshold. 241CREATE PERFETTO FUNCTION android_binder_transaction_slices_for_startup( 242 -- Startup id. 243 startup_id INT, 244 -- Only return slices with duration over threshold. 245 threshold DOUBLE) 246RETURNS TABLE( 247 -- Slice id. 248 id INT, 249 -- Slice duration. 250 slice_dur INT, 251 -- Name of the thread with slice. 252 thread_name STRING, 253 -- Name of the process with slice. 254 process STRING, 255 -- Arg set id. 256 arg_set_id INT, 257 -- Whether is main thread. 258 is_main_thread BOOL 259) AS 260SELECT 261 slice_id as id, 262 slice_dur, 263 thread_name, 264 process.name as process, 265 s.arg_set_id, 266 is_main_thread 267FROM android_thread_slices_for_all_startups s 268JOIN process ON ( 269 EXTRACT_ARG(s.arg_set_id, "destination process") = process.pid 270) 271WHERE startup_id = $startup_id 272 AND slice_name GLOB "binder transaction" 273 AND slice_dur > $threshold; 274 275-- Returns duration of startup for slice name. 276-- 277-- Sums duration of all slices of startup with provided name. 278CREATE PERFETTO FUNCTION android_sum_dur_for_startup_and_slice( 279 -- Startup id. 280 startup_id LONG, 281 -- Slice name. 282 slice_name STRING) 283-- Sum of duration. 284RETURNS INT AS 285SELECT SUM(slice_dur) 286FROM android_thread_slices_for_all_startups 287WHERE startup_id = $startup_id 288 AND slice_name GLOB $slice_name; 289 290-- Returns duration of startup for slice name on main thread. 291-- 292-- Sums duration of all slices of startup with provided name only on main thread. 293CREATE PERFETTO FUNCTION android_sum_dur_on_main_thread_for_startup_and_slice( 294 -- Startup id. 295 startup_id LONG, 296 -- Slice name. 297 slice_name STRING) 298-- Sum of duration. 299RETURNS INT AS 300SELECT SUM(slice_dur) 301FROM android_thread_slices_for_all_startups 302WHERE startup_id = $startup_id 303 AND slice_name GLOB $slice_name 304 AND is_main_thread; 305