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-- 16 17-- Create the base tables and views containing the launch spans. 18SELECT RUN_METRIC('android/startup/launches.sql'); 19SELECT RUN_METRIC('android/startup/hsc.sql'); 20SELECT RUN_METRIC('android/process_metadata.sql'); 21 22-- Create the base CPU span join table. 23SELECT RUN_METRIC('android/android_cpu_agg.sql'); 24 25-- Create a span join safe launches view; since both views 26-- being span joined have an "id" column, we need to rename 27-- the id column for launches to disambiguate the two. 28DROP VIEW IF EXISTS launches_span_join_safe; 29CREATE VIEW launches_span_join_safe AS 30SELECT ts, dur, id AS launch_id 31FROM launches; 32 33-- Span join the CPU table with the launches table to get the 34-- breakdown per-cpu. 35DROP TABLE IF EXISTS cpu_freq_sched_per_thread_per_launch; 36CREATE VIRTUAL TABLE cpu_freq_sched_per_thread_per_launch 37USING SPAN_JOIN( 38 launches_span_join_safe, 39 cpu_freq_sched_per_thread PARTITIONED cpu 40); 41 42SELECT RUN_METRIC('android/cpu_info.sql'); 43 44DROP VIEW IF EXISTS mcycles_per_core_type_per_launch; 45CREATE VIEW mcycles_per_core_type_per_launch AS 46SELECT 47 launch_id, 48 IFNULL(core_type_per_cpu.core_type, 'unknown') AS core_type, 49 CAST(SUM(dur * freq_khz / 1000) / 1e9 AS INT) AS mcycles 50FROM cpu_freq_sched_per_thread_per_launch 51LEFT JOIN core_type_per_cpu USING (cpu) 52WHERE utid != 0 53GROUP BY 1, 2; 54 55-- Slices for forked processes. Never present in hot starts. 56-- Prefer this over process start_ts, since the process might have 57-- been preforked. 58DROP VIEW IF EXISTS zygote_fork_slice; 59CREATE VIEW zygote_fork_slice AS 60SELECT slice.ts, slice.dur, STR_SPLIT(slice.name, ": ", 1) AS process_name 61FROM slice WHERE name GLOB 'Start proc: *'; 62 63DROP TABLE IF EXISTS zygote_forks_by_id; 64CREATE TABLE zygote_forks_by_id AS 65SELECT 66 launches.id, 67 zygote_fork_slice.ts, 68 zygote_fork_slice.dur 69FROM zygote_fork_slice 70JOIN launches 71ON (launches.ts < zygote_fork_slice.ts 72 AND zygote_fork_slice.ts + zygote_fork_slice.dur < launches.ts_end 73 AND zygote_fork_slice.process_name = launches.package 74); 75 76DROP VIEW IF EXISTS launch_main_threads; 77CREATE VIEW launch_main_threads AS 78SELECT 79 launches.ts AS ts, 80 launches.dur AS dur, 81 launches.id AS launch_id, 82 thread.utid AS utid 83FROM launches 84JOIN launch_processes ON launches.id = launch_processes.launch_id 85JOIN process USING(upid) 86JOIN thread ON (process.upid = thread.upid AND process.pid = thread.tid) 87ORDER BY ts; 88 89DROP VIEW IF EXISTS thread_state_extended; 90CREATE VIEW thread_state_extended AS 91SELECT 92 ts, 93 IIF(dur = -1, (SELECT end_ts FROM trace_bounds), dur) AS dur, 94 utid, 95 state 96FROM thread_state; 97 98DROP TABLE IF EXISTS main_thread_state; 99CREATE VIRTUAL TABLE main_thread_state 100USING SPAN_JOIN( 101 launch_main_threads PARTITIONED utid, 102 thread_state_extended PARTITIONED utid); 103 104DROP VIEW IF EXISTS launch_by_thread_state; 105CREATE VIEW launch_by_thread_state AS 106SELECT launch_id, state, SUM(dur) AS dur 107FROM main_thread_state 108GROUP BY 1, 2; 109 110-- Tracks all main thread process threads. 111DROP VIEW IF EXISTS launch_threads; 112CREATE VIEW launch_threads AS 113SELECT 114 launches.id AS launch_id, 115 launches.ts AS ts, 116 launches.dur AS dur, 117 thread.utid AS utid, 118 thread.name AS thread_name 119FROM launches 120JOIN launch_processes ON (launches.id = launch_processes.launch_id) 121JOIN thread ON (launch_processes.upid = thread.upid); 122 123-- Tracks all slices for the main process threads 124DROP VIEW IF EXISTS main_process_slice_unaggregated; 125CREATE VIEW main_process_slice_unaggregated AS 126SELECT 127 launch_threads.launch_id AS launch_id, 128 launch_threads.utid AS utid, 129 launch_threads.thread_name AS thread_name, 130 slice.id AS slice_id, 131 slice.arg_set_id AS arg_set_id, 132 slice.name AS slice_name, 133 slice.ts AS slice_ts, 134 slice.dur AS slice_dur 135FROM launch_threads 136JOIN thread_track USING (utid) 137JOIN slice ON ( 138 slice.track_id = thread_track.id 139 AND slice.ts BETWEEN launch_threads.ts AND launch_threads.ts + launch_threads.dur) 140WHERE slice.name IN ( 141 'PostFork', 142 'ActivityThreadMain', 143 'bindApplication', 144 'activityStart', 145 'activityRestart', 146 'activityResume', 147 'inflate', 148 'ResourcesManager#getResources', 149 'binder transaction') 150 OR slice.name GLOB 'performResume:*' 151 OR slice.name GLOB 'performCreate:*' 152 OR slice.name GLOB 'location=* status=* filter=* reason=*' 153 OR slice.name GLOB 'OpenDexFilesFromOat*' 154 OR slice.name GLOB 'VerifyClass*' 155 OR slice.name GLOB 'Choreographer#doFrame*' 156 OR slice.name GLOB 'JIT compiling*' 157 OR slice.name GLOB '*mark sweep GC' 158 OR slice.name GLOB '*concurrent copying GC' 159 OR slice.name GLOB '*semispace GC'; 160 161DROP TABLE IF EXISTS main_process_slice; 162CREATE TABLE main_process_slice AS 163SELECT 164 launch_id, 165 CASE 166 WHEN slice_name GLOB 'OpenDexFilesFromOat*' THEN 'OpenDexFilesFromOat' 167 WHEN slice_name GLOB 'VerifyClass*' THEN 'VerifyClass' 168 WHEN slice_name GLOB 'JIT compiling*' THEN 'JIT compiling' 169 WHEN slice_name GLOB '*mark sweep GC' THEN 'GC' 170 WHEN slice_name GLOB '*concurrent copying GC' THEN 'GC' 171 WHEN slice_name GLOB '*semispace GC' THEN 'GC' 172 ELSE slice_name 173 END AS name, 174 AndroidStartupMetric_Slice( 175 'dur_ns', SUM(slice_dur), 176 'dur_ms', SUM(slice_dur) / 1e6 177 ) AS slice_proto 178FROM main_process_slice_unaggregated 179GROUP BY 1, 2; 180 181DROP TABLE IF EXISTS report_fully_drawn_per_launch; 182CREATE TABLE report_fully_drawn_per_launch AS 183WITH report_fully_drawn_launch_slices AS ( 184 SELECT 185 launches.id AS launch_id, 186 launches.ts AS launch_ts, 187 min(slice.ts) as report_fully_drawn_ts 188 FROM launches 189 JOIN launch_processes ON (launches.id = launch_processes.launch_id) 190 JOIN thread ON (launch_processes.upid = thread.upid) 191 JOIN thread_track USING (utid) 192 JOIN slice ON ( 193 slice.track_id = thread_track.id 194 AND slice.ts >= launches.ts) 195 WHERE slice.name GLOB 'reportFullyDrawn*' 196 GROUP BY launches.id 197) 198SELECT 199 launch_id, 200 report_fully_drawn_ts - launch_ts as report_fully_drawn_dur 201FROM report_fully_drawn_launch_slices; 202 203DROP VIEW IF EXISTS to_event_protos; 204CREATE VIEW to_event_protos AS 205SELECT 206 slice.name as slice_name, 207 launch_id, 208 AndroidStartupMetric_Slice( 209 'dur_ns', slice.ts - l.ts, 210 'dur_ms', (slice.ts - l.ts) / 1e6 211 ) as slice_proto 212FROM launch_main_threads l 213JOIN thread_track USING (utid) 214JOIN slice ON ( 215 slice.track_id = thread_track.id 216 AND slice.ts BETWEEN l.ts AND l.ts + l.dur); 217 218DROP VIEW IF EXISTS gc_slices; 219CREATE VIEW gc_slices AS 220 SELECT 221 slice_ts AS ts, 222 slice_dur AS dur, 223 utid, 224 launch_id 225 FROM main_process_slice_unaggregated 226 WHERE ( 227 slice_name GLOB '*mark sweep GC' 228 OR slice_name GLOB '*concurrent copying GC' 229 OR slice_name GLOB '*semispace GC'); 230 231DROP TABLE IF EXISTS gc_slices_by_state; 232CREATE VIRTUAL TABLE gc_slices_by_state 233USING SPAN_JOIN(gc_slices PARTITIONED utid, thread_state_extended PARTITIONED utid); 234 235DROP TABLE IF EXISTS gc_slices_by_state_materialized; 236CREATE TABLE gc_slices_by_state_materialized AS 237SELECT launch_id, SUM(dur) as sum_dur 238FROM gc_slices_by_state 239WHERE state = 'Running' 240GROUP BY launch_id; 241 242DROP TABLE IF EXISTS launch_threads_cpu; 243CREATE VIRTUAL TABLE launch_threads_cpu 244USING SPAN_JOIN(launch_threads PARTITIONED utid, thread_state_extended PARTITIONED utid); 245 246DROP TABLE IF EXISTS launch_threads_cpu_materialized; 247CREATE TABLE launch_threads_cpu_materialized AS 248SELECT launch_id, SUM(dur) as sum_dur 249FROM launch_threads_cpu 250WHERE thread_name = 'Jit thread pool' AND state = 'Running' 251GROUP BY launch_id; 252 253DROP TABLE IF EXISTS activity_names_materialized; 254CREATE TABLE activity_names_materialized AS 255SELECT launch_id, slice_name, slice_ts 256FROM main_process_slice_unaggregated 257WHERE (slice_name GLOB 'performResume:*' OR slice_name GLOB 'performCreate:*'); 258 259DROP TABLE IF EXISTS jit_compiled_methods_materialized; 260CREATE TABLE jit_compiled_methods_materialized AS 261SELECT 262 launch_id, 263 COUNT(1) as count 264FROM main_process_slice_unaggregated 265WHERE 266 slice_name GLOB 'JIT compiling*' 267 AND thread_name = 'Jit thread pool' 268GROUP BY launch_id; 269 270DROP TABLE IF EXISTS long_binder_transactions; 271CREATE TABLE long_binder_transactions AS 272SELECT 273 s.slice_id, 274 s.launch_id, 275 s.slice_dur, 276 s.thread_name, 277 EXTRACT_ARG(s.arg_set_id, 'destination name') AS destination_thread, 278 process.name AS destination_process, 279 EXTRACT_ARG(s.arg_set_id, 'flags') AS flags, 280 EXTRACT_ARG(s.arg_set_id, 'code') AS code, 281 EXTRACT_ARG(s.arg_set_id, 'data_size') AS data_size 282FROM 283 main_process_slice_unaggregated s 284JOIN process ON (EXTRACT_ARG(s.arg_set_id, 'destination process') = process.pid) 285WHERE 286 s.slice_name = 'binder transaction' AND 287 s.slice_dur >= 5e7; 288 289SELECT CREATE_FUNCTION( 290 'MAIN_PROCESS_SLICE_PROTO(launch_id LONG, name STRING)', 291 'PROTO', ' 292 SELECT slice_proto 293 FROM main_process_slice s 294 WHERE s.launch_id = $launch_id AND name GLOB $name 295 LIMIT 1 296 '); 297 298DROP VIEW IF EXISTS startup_view; 299CREATE VIEW startup_view AS 300SELECT 301 AndroidStartupMetric_Startup( 302 'startup_id', launches.id, 303 'package_name', launches.package, 304 'process_name', ( 305 SELECT p.name 306 FROM launch_processes lp 307 JOIN process p USING (upid) 308 WHERE lp.launch_id = launches.id 309 LIMIT 1 310 ), 311 'process', ( 312 SELECT m.metadata 313 FROM process_metadata m 314 JOIN launch_processes p USING (upid) 315 WHERE p.launch_id = launches.id 316 LIMIT 1 317 ), 318 'activities', ( 319 SELECT RepeatedField(AndroidStartupMetric_Activity( 320 'name', (SELECT STR_SPLIT(s.slice_name, ':', 1)), 321 'method', (SELECT STR_SPLIT(s.slice_name, ':', 0)), 322 'ts_method_start', s.slice_ts 323 )) 324 FROM activity_names_materialized s 325 WHERE s.launch_id = launches.id 326 ), 327 'long_binder_transactions', ( 328 SELECT RepeatedField(AndroidStartupMetric_BinderTransaction( 329 'duration', AndroidStartupMetric_Slice( 330 'dur_ns', lbt.slice_dur, 331 'dur_ms', lbt.slice_dur / 1e6 332 ), 333 'thread', lbt.thread_name, 334 'destination_thread', lbt.destination_thread, 335 'destination_process', lbt.destination_process, 336 'flags', lbt.flags, 337 'code', lbt.code, 338 'data_size', lbt.data_size 339 )) 340 FROM long_binder_transactions lbt 341 WHERE lbt.launch_id = launches.id 342 ), 343 'zygote_new_process', EXISTS(SELECT TRUE FROM zygote_forks_by_id WHERE id = launches.id), 344 'activity_hosting_process_count', ( 345 SELECT COUNT(1) FROM launch_processes p 346 WHERE p.launch_id = launches.id 347 ), 348 'event_timestamps', AndroidStartupMetric_EventTimestamps( 349 'intent_received', launches.ts, 350 'first_frame', launches.ts_end 351 ), 352 'to_first_frame', AndroidStartupMetric_ToFirstFrame( 353 'dur_ns', launches.dur, 354 'dur_ms', launches.dur / 1e6, 355 'main_thread_by_task_state', AndroidStartupMetric_TaskStateBreakdown( 356 'running_dur_ns', IFNULL( 357 ( 358 SELECT dur FROM launch_by_thread_state l 359 WHERE l.launch_id = launches.id AND state = 'Running' 360 ), 0), 361 'runnable_dur_ns', IFNULL( 362 ( 363 SELECT dur FROM launch_by_thread_state l 364 WHERE l.launch_id = launches.id AND state = 'R' 365 ), 0), 366 'uninterruptible_sleep_dur_ns', IFNULL( 367 ( 368 SELECT dur FROM launch_by_thread_state l 369 WHERE l.launch_id = launches.id AND (state = 'D' or state = 'DK') 370 ), 0), 371 'interruptible_sleep_dur_ns', IFNULL( 372 ( 373 SELECT dur FROM launch_by_thread_state l 374 WHERE l.launch_id = launches.id AND state = 'S' 375 ), 0) 376 ), 377 'mcycles_by_core_type', AndroidStartupMetric_McyclesByCoreType( 378 'little', ( 379 SELECT mcycles 380 FROM mcycles_per_core_type_per_launch m 381 WHERE m.launch_id = launches.id AND m.core_type = 'little' 382 ), 383 'big', ( 384 SELECT mcycles 385 FROM mcycles_per_core_type_per_launch m 386 WHERE m.launch_id = launches.id AND m.core_type = 'big' 387 ), 388 'bigger', ( 389 SELECT mcycles 390 FROM mcycles_per_core_type_per_launch m 391 WHERE m.launch_id = launches.id AND m.core_type = 'bigger' 392 ), 393 'unknown', ( 394 SELECT mcycles 395 FROM mcycles_per_core_type_per_launch m 396 WHERE m.launch_id = launches.id AND m.core_type = 'unknown' 397 ) 398 ), 399 'to_post_fork', ( 400 SELECT slice_proto 401 FROM to_event_protos p 402 WHERE p.launch_id = launches.id AND slice_name = 'PostFork' 403 ), 404 'to_activity_thread_main', ( 405 SELECT slice_proto 406 FROM to_event_protos p 407 WHERE p.launch_id = launches.id AND slice_name = 'ActivityThreadMain' 408 ), 409 'to_bind_application', ( 410 SELECT slice_proto 411 FROM to_event_protos p 412 WHERE p.launch_id = launches.id AND slice_name = 'bindApplication' 413 ), 414 'other_processes_spawned_count', ( 415 SELECT COUNT(1) FROM process 416 WHERE (process.name IS NULL OR process.name != launches.package) 417 AND process.start_ts BETWEEN launches.ts AND launches.ts + launches.dur 418 ), 419 'time_activity_manager', ( 420 SELECT AndroidStartupMetric_Slice( 421 'dur_ns', l.ts - launches.ts, 422 'dur_ms', (l.ts - launches.ts) / 1e6 423 ) 424 FROM launching_events l 425 WHERE l.ts BETWEEN launches.ts AND launches.ts + launches.dur 426 ), 427 'time_post_fork', MAIN_PROCESS_SLICE_PROTO(launches.id, 'PostFork'), 428 'time_activity_thread_main', MAIN_PROCESS_SLICE_PROTO(launches.id, 'ActivityThreadMain'), 429 'time_bind_application', MAIN_PROCESS_SLICE_PROTO(launches.id, 'bindApplication'), 430 'time_activity_start', MAIN_PROCESS_SLICE_PROTO(launches.id, 'activityStart'), 431 'time_activity_resume', MAIN_PROCESS_SLICE_PROTO(launches.id, 'activityResume'), 432 'time_activity_restart', MAIN_PROCESS_SLICE_PROTO(launches.id, 'activityRestart'), 433 'time_choreographer', MAIN_PROCESS_SLICE_PROTO(launches.id, 'Choreographer#doFrame*'), 434 'time_inflate', MAIN_PROCESS_SLICE_PROTO(launches.id, 'inflate'), 435 'time_get_resources', MAIN_PROCESS_SLICE_PROTO(launches.id, 'ResourcesManager#getResources'), 436 'time_dex_open', MAIN_PROCESS_SLICE_PROTO(launches.id, 'OpenDexFilesFromOat'), 437 'time_verify_class', MAIN_PROCESS_SLICE_PROTO(launches.id, 'VerifyClass'), 438 'time_gc_total', MAIN_PROCESS_SLICE_PROTO(launches.id, 'GC'), 439 'time_before_start_process', ( 440 SELECT AndroidStartupMetric_Slice( 441 'dur_ns', ts - launches.ts, 442 'dur_ms', (ts - launches.ts) / 1e6 443 ) 444 FROM zygote_forks_by_id z 445 WHERE z.id = launches.id 446 ), 447 'time_during_start_process', ( 448 SELECT AndroidStartupMetric_Slice( 449 'dur_ns', dur, 450 'dur_ms', dur / 1e6 451 ) 452 FROM zygote_forks_by_id z 453 WHERE z.id = launches.id 454 ), 455 'jit_compiled_methods', ( 456 SELECT count 457 FROM jit_compiled_methods_materialized s 458 WHERE s.launch_id = launches.id 459 ), 460 'time_jit_thread_pool_on_cpu', ( 461 SELECT 462 NULL_IF_EMPTY(AndroidStartupMetric_Slice( 463 'dur_ns', sum_dur, 464 'dur_ms', sum_dur / 1e6 465 )) 466 FROM launch_threads_cpu_materialized 467 WHERE launch_id = launches.id 468 ), 469 'time_gc_on_cpu', ( 470 SELECT 471 NULL_IF_EMPTY(AndroidStartupMetric_Slice( 472 'dur_ns', sum_dur, 473 'dur_ms', sum_dur / 1e6 474 )) 475 FROM gc_slices_by_state_materialized 476 WHERE launch_id = launches.id 477 ) 478 ), 479 'hsc', ( 480 SELECT NULL_IF_EMPTY(AndroidStartupMetric_HscMetrics( 481 'full_startup', ( 482 SELECT AndroidStartupMetric_Slice( 483 'dur_ns', h.ts_total, 484 'dur_ms', h.ts_total / 1e6 485 ) 486 FROM hsc_based_startup_times h 487 WHERE h.id = launches.id 488 ) 489 )) 490 ), 491 'report_fully_drawn', ( 492 SELECT NULL_IF_EMPTY(AndroidStartupMetric_Slice( 493 'dur_ns', report_fully_drawn_dur, 494 'dur_ms', report_fully_drawn_dur / 1e6 495 )) 496 FROM report_fully_drawn_per_launch r 497 WHERE r.launch_id = launches.id 498 ), 499 'optimization_status',( 500 SELECT RepeatedField(AndroidStartupMetric_OptimizationStatus( 501 'location', SUBSTR(STR_SPLIT(name, ' status=', 0), LENGTH('location=') + 1), 502 'odex_status', STR_SPLIT(STR_SPLIT(name, ' status=', 1), ' filter=', 0), 503 'compilation_filter', STR_SPLIT(STR_SPLIT(name, ' filter=', 1), ' reason=', 0), 504 'compilation_reason', STR_SPLIT(name, ' reason=', 1) 505 )) 506 FROM main_process_slice s 507 WHERE name GLOB 'location=* status=* filter=* reason=*' 508 ) 509 ) as startup 510FROM launches; 511 512DROP VIEW IF EXISTS android_startup_event; 513CREATE VIEW android_startup_event AS 514SELECT 515 'slice' as track_type, 516 'Android App Startups' as track_name, 517 l.ts as ts, 518 l.dur as dur, 519 l.package as slice_name 520FROM launches l; 521 522DROP VIEW IF EXISTS android_startup_output; 523CREATE VIEW android_startup_output AS 524SELECT 525 AndroidStartupMetric( 526 'startup', ( 527 SELECT RepeatedField(startup) FROM startup_view 528 ) 529 ); 530