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; 17 18INCLUDE PERFETTO MODULE android.startup.startups_maxsdk28; 19 20INCLUDE PERFETTO MODULE android.startup.startups_minsdk29; 21 22INCLUDE PERFETTO MODULE android.startup.startups_minsdk33; 23 24INCLUDE PERFETTO MODULE android.version; 25 26CREATE PERFETTO TABLE _android_startups_raw AS 27WITH 28 version AS ( 29 SELECT 30 CASE 31 WHEN _android_sdk_version() >= 33 32 THEN 33 33 WHEN _android_sdk_version() >= 29 34 THEN 29 35 WHEN _android_sdk_version() IS NOT NULL 36 THEN 28 37 WHEN ( 38 SELECT 39 count() 40 FROM slice 41 WHERE 42 name GLOB 'launchingActivity#*:*' 43 ) > 0 44 THEN 33 45 WHEN ( 46 SELECT 47 count() 48 FROM slice 49 WHERE 50 name GLOB 'MetricsLogger:*' 51 ) > 0 52 THEN 29 53 ELSE 28 54 END AS v 55 ) 56SELECT 57 _auto_id AS startup_id, 58 ts, 59 ts_end, 60 dur, 61 package, 62 startup_type 63FROM _startups_maxsdk28 64WHERE 65 ( 66 SELECT 67 v 68 FROM version 69 ) = 28 70UNION ALL 71SELECT 72 _auto_id AS startup_id, 73 ts, 74 ts_end, 75 dur, 76 package, 77 startup_type 78FROM _startups_minsdk29 79WHERE 80 ( 81 SELECT 82 v 83 FROM version 84 ) = 29 85UNION ALL 86SELECT 87 startup_id, 88 ts, 89 ts_end, 90 dur, 91 package, 92 startup_type 93FROM _startups_minsdk33 94WHERE 95 ( 96 SELECT 97 v 98 FROM version 99 ) = 33; 100 101-- Create a table containing only the slices which are necessary for determining 102-- whether a startup happened. 103CREATE PERFETTO TABLE _startup_indicator_slices AS 104SELECT 105 ts, 106 name, 107 track_id 108FROM slice 109WHERE 110 name IN ('bindApplication', 'activityStart', 'activityResume'); 111 112CREATE PERFETTO FUNCTION _startup_indicator_slice_count( 113 start_ts TIMESTAMP, 114 end_ts TIMESTAMP, 115 utid JOINID(thread.id), 116 name STRING 117) 118RETURNS LONG AS 119SELECT 120 count(1) 121FROM thread_track AS t 122JOIN _startup_indicator_slices AS s 123 ON s.track_id = t.id 124WHERE 125 t.utid = $utid AND s.ts >= $start_ts AND s.ts < $end_ts AND s.name = $name; 126 127-- Maps a startup to the set of processes that handled the activity start. 128-- 129-- The vast majority of cases should be a single process. However it is 130-- possible that the process dies during the activity startup and is respawned. 131CREATE PERFETTO TABLE android_startup_processes ( 132 -- Startup id. 133 startup_id LONG, 134 -- Upid of process on which activity started. 135 upid JOINID(process.id), 136 -- Pid of process on which activity started. 137 pid LONG, 138 -- Type of the startup. 139 startup_type STRING 140) AS 141-- This is intentionally a materialized query. For some reason, if we don't 142-- materialize, we end up with a query which is an order of magnitude slower :( 143WITH 144 startup_with_type AS MATERIALIZED ( 145 SELECT 146 startup_id, 147 upid, 148 pid, 149 CASE 150 -- type parsed from platform event takes precedence if available 151 WHEN startup_type IS NOT NULL 152 THEN startup_type 153 WHEN bind_app > 0 AND a_start > 0 AND a_resume > 0 154 THEN 'cold' 155 WHEN a_start > 0 AND a_resume > 0 156 THEN 'warm' 157 WHEN a_resume > 0 158 THEN 'hot' 159 ELSE NULL 160 END AS startup_type 161 FROM ( 162 SELECT 163 l.startup_id, 164 l.startup_type, 165 p.upid, 166 p.pid, 167 _startup_indicator_slice_count(l.ts, l.ts_end, t.utid, 'bindApplication') AS bind_app, 168 _startup_indicator_slice_count(l.ts, l.ts_end, t.utid, 'activityStart') AS a_start, 169 _startup_indicator_slice_count(l.ts, l.ts_end, t.utid, 'activityResume') AS a_resume 170 FROM _android_startups_raw AS l 171 JOIN android_process_metadata AS p 172 ON ( 173 l.package = p.package_name 174 -- If the package list data source was not enabled in the trace, nothing 175 -- will match the above constraint so also match any process whose name 176 -- is a prefix of the package name. 177 OR ( 178 ( 179 SELECT 180 count(1) = 0 181 FROM package_list 182 ) 183 AND p.process_name GLOB l.package || '*' 184 ) 185 ) 186 JOIN thread AS t 187 ON ( 188 p.upid = t.upid AND t.is_main_thread 189 ) 190 -- Filter out the non-startup processes with the same package name as that of a startup. 191 WHERE 192 a_resume > 0 193 ) 194 ) 195SELECT 196 * 197FROM startup_with_type 198WHERE 199 startup_type IS NOT NULL; 200 201-- All activity startups in the trace by startup id. 202-- Populated by different scripts depending on the platform version/contents. 203CREATE PERFETTO VIEW android_startups ( 204 -- Startup id. 205 startup_id ID, 206 -- Timestamp of startup start. 207 ts TIMESTAMP, 208 -- Timestamp of startup end. 209 ts_end LONG, 210 -- Startup duration. 211 dur DURATION, 212 -- Package name. 213 package STRING, 214 -- Startup type. 215 startup_type STRING 216) AS 217SELECT 218 r.startup_id, 219 r.ts, 220 r.ts_end, 221 r.dur, 222 r.package, 223 coalesce(r.startup_type, max(p.startup_type)) AS startup_type 224FROM _android_startups_raw AS r 225LEFT JOIN android_startup_processes AS p 226 USING (startup_id) 227GROUP BY 228 r.startup_id; 229 230-- Maps a startup to the set of threads on processes that handled the 231-- activity start. 232CREATE PERFETTO VIEW android_startup_threads ( 233 -- Startup id. 234 startup_id LONG, 235 -- Timestamp of start. 236 ts TIMESTAMP, 237 -- Duration of startup. 238 dur DURATION, 239 -- Upid of process involved in startup. 240 upid JOINID(process.id), 241 -- Pid if process involved in startup. 242 pid LONG, 243 -- Utid of the thread. 244 utid JOINID(thread.id), 245 -- Tid of the thread. 246 tid LONG, 247 -- Name of the thread. 248 thread_name STRING, 249 -- Thread is a main thread. 250 is_main_thread BOOL 251) AS 252SELECT 253 startups.startup_id, 254 startups.ts, 255 startups.dur, 256 android_startup_processes.upid, 257 android_startup_processes.pid, 258 thread.utid, 259 thread.tid, 260 thread.name AS thread_name, 261 thread.is_main_thread AS is_main_thread 262FROM android_startups AS startups 263JOIN android_startup_processes 264 USING (startup_id) 265JOIN thread 266 USING (upid); 267 268--- 269--- Functions 270--- 271 272-- All the slices for all startups in trace. 273-- 274-- Generally, this view should not be used. Instead, use one of the view functions related 275-- to the startup slices which are created from this table. 276CREATE PERFETTO VIEW android_thread_slices_for_all_startups ( 277 -- Timestamp of startup. 278 startup_ts TIMESTAMP, 279 -- Timestamp of startup end. 280 startup_ts_end LONG, 281 -- Startup id. 282 startup_id LONG, 283 -- UTID of thread with slice. 284 utid JOINID(thread.id), 285 --Tid of thread. 286 tid LONG, 287 -- Name of thread. 288 thread_name STRING, 289 -- Whether it is main thread. 290 is_main_thread BOOL, 291 -- Arg set id. 292 arg_set_id ARGSETID, 293 -- Slice id. 294 slice_id JOINID(slice.id), 295 -- Name of slice. 296 slice_name STRING, 297 -- Timestamp of slice start. 298 slice_ts TIMESTAMP, 299 -- Slice duration. 300 slice_dur LONG 301) AS 302SELECT 303 st.ts AS startup_ts, 304 st.ts + st.dur AS startup_ts_end, 305 st.startup_id, 306 st.utid, 307 st.tid, 308 st.thread_name, 309 st.is_main_thread, 310 slice.arg_set_id, 311 slice.id AS slice_id, 312 slice.name AS slice_name, 313 slice.ts AS slice_ts, 314 slice.dur AS slice_dur 315FROM android_startup_threads AS st 316JOIN thread_track 317 USING (utid) 318JOIN slice 319 ON ( 320 slice.track_id = thread_track.id 321 ) 322WHERE 323 slice.ts BETWEEN st.ts AND st.ts + st.dur; 324 325-- Given a startup id and GLOB for a slice name, returns matching slices with data. 326CREATE PERFETTO FUNCTION android_slices_for_startup_and_slice_name( 327 -- Startup id. 328 startup_id LONG, 329 -- Glob of the slice. 330 slice_name STRING 331) 332RETURNS TABLE ( 333 -- Id of the slice. 334 slice_id JOINID(slice.id), 335 -- Name of the slice. 336 slice_name STRING, 337 -- Timestamp of start of the slice. 338 slice_ts TIMESTAMP, 339 -- Duration of the slice. 340 slice_dur DURATION, 341 -- Name of the thread with the slice. 342 thread_name STRING, 343 -- Tid of the thread with the slice. 344 tid LONG, 345 -- Arg set id. 346 arg_set_id ARGSETID 347) AS 348SELECT 349 slice_id, 350 slice_name, 351 slice_ts, 352 slice_dur, 353 thread_name, 354 tid, 355 arg_set_id 356FROM android_thread_slices_for_all_startups 357WHERE 358 startup_id = $startup_id AND slice_name GLOB $slice_name; 359 360-- A Perfetto view that lists matching slices for class loading during app startup. 361CREATE PERFETTO VIEW android_class_loading_for_startup ( 362 -- Id of the slice. 363 slice_id JOINID(slice.id), 364 -- Startup id. 365 startup_id LONG, 366 -- Name of the slice. 367 slice_name STRING, 368 -- Timestamp of start of the slice. 369 slice_ts TIMESTAMP, 370 -- Duration of the slice. 371 slice_dur DURATION, 372 -- Name of the thread with the slice. 373 thread_name STRING, 374 -- Tid of the thread with the slice. 375 tid LONG, 376 -- Arg set id. 377 arg_set_id ARGSETID 378) AS 379SELECT 380 slice_id, 381 startup_id, 382 slice_name, 383 slice_ts, 384 slice_dur, 385 thread_name, 386 tid, 387 arg_set_id 388FROM android_thread_slices_for_all_startups 389WHERE 390 slice_name GLOB "L*;"; 391 392-- Returns binder transaction slices for a given startup id with duration over threshold. 393CREATE PERFETTO FUNCTION android_binder_transaction_slices_for_startup( 394 -- Startup id. 395 startup_id LONG, 396 -- Only return slices with duration over threshold. 397 threshold DOUBLE 398) 399RETURNS TABLE ( 400 -- Slice id. 401 id LONG, 402 -- Slice duration. 403 slice_dur DURATION, 404 -- Name of the thread with slice. 405 thread_name STRING, 406 -- Name of the process with slice. 407 process STRING, 408 -- Arg set id. 409 arg_set_id ARGSETID, 410 -- Whether is main thread. 411 is_main_thread BOOL 412) AS 413SELECT 414 slice_id AS id, 415 slice_dur, 416 thread_name, 417 process.name AS process, 418 s.arg_set_id, 419 is_main_thread 420FROM android_thread_slices_for_all_startups AS s 421JOIN process 422 ON ( 423 extract_arg(s.arg_set_id, "destination process") = process.pid 424 ) 425WHERE 426 startup_id = $startup_id 427 AND slice_name GLOB "binder transaction" 428 AND slice_dur > $threshold; 429 430-- Returns duration of startup for slice name. 431-- 432-- Sums duration of all slices of startup with provided name. 433CREATE PERFETTO FUNCTION android_sum_dur_for_startup_and_slice( 434 -- Startup id. 435 startup_id LONG, 436 -- Slice name. 437 slice_name STRING 438) 439-- Sum of duration. 440RETURNS LONG AS 441SELECT 442 sum(slice_dur) 443FROM android_thread_slices_for_all_startups 444WHERE 445 startup_id = $startup_id AND slice_name GLOB $slice_name; 446 447-- Returns duration of startup for slice name on main thread. 448-- 449-- Sums duration of all slices of startup with provided name only on main thread. 450CREATE PERFETTO FUNCTION android_sum_dur_on_main_thread_for_startup_and_slice( 451 -- Startup id. 452 startup_id LONG, 453 -- Slice name. 454 slice_name STRING 455) 456-- Sum of duration. 457RETURNS LONG AS 458SELECT 459 sum(slice_dur) 460FROM android_thread_slices_for_all_startups 461WHERE 462 startup_id = $startup_id AND slice_name GLOB $slice_name AND is_main_thread; 463