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/android_startup_launches.sql'); 19SELECT RUN_METRIC('android/process_metadata.sql'); 20SELECT RUN_METRIC('android/hsc_startups.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 LIKE '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.name AS slice_name, 131 slice.ts AS slice_ts, 132 slice.dur AS slice_dur 133FROM launch_threads 134JOIN thread_track USING (utid) 135JOIN slice ON ( 136 slice.track_id = thread_track.id 137 AND slice.ts BETWEEN launch_threads.ts AND launch_threads.ts + launch_threads.dur) 138WHERE slice.name IN ( 139 'PostFork', 140 'ActivityThreadMain', 141 'bindApplication', 142 'activityStart', 143 'activityRestart', 144 'activityResume', 145 'inflate', 146 'ResourcesManager#getResources', 147 'binder transaction') 148 OR slice.name LIKE 'performResume:%' 149 OR slice.name LIKE 'performCreate:%' 150 OR slice.name LIKE 'location=% status=% filter=% reason=%' 151 OR slice.name LIKE 'OpenDexFilesFromOat%' 152 OR slice.name LIKE 'VerifyClass%' 153 OR slice.name LIKE 'Choreographer#doFrame%' 154 OR slice.name LIKE 'JIT compiling%' 155 OR slice.name LIKE '%mark sweep GC' 156 OR slice.name LIKE '%concurrent copying GC' 157 OR slice.name LIKE '%semispace GC'; 158 159DROP TABLE IF EXISTS main_process_slice; 160CREATE TABLE main_process_slice AS 161SELECT 162 launch_id, 163 CASE 164 WHEN slice_name LIKE 'OpenDexFilesFromOat%' THEN 'OpenDexFilesFromOat' 165 WHEN slice_name LIKE 'VerifyClass%' THEN 'VerifyClass' 166 WHEN slice_name LIKE 'JIT compiling%' THEN 'JIT compiling' 167 WHEN slice_name LIKE '%mark sweep GC' THEN 'GC' 168 WHEN slice_name LIKE '%concurrent copying GC' THEN 'GC' 169 WHEN slice_name LIKE '%semispace GC' THEN 'GC' 170 ELSE slice_name 171 END AS name, 172 AndroidStartupMetric_Slice( 173 'dur_ns', SUM(slice_dur), 174 'dur_ms', SUM(slice_dur) / 1e6 175 ) AS slice_proto 176FROM main_process_slice_unaggregated 177GROUP BY 1, 2; 178 179DROP TABLE IF EXISTS report_fully_drawn_per_launch; 180CREATE TABLE report_fully_drawn_per_launch AS 181WITH report_fully_drawn_launch_slices AS ( 182 SELECT 183 launches.id AS launch_id, 184 launches.ts AS launch_ts, 185 min(slice.ts) as report_fully_drawn_ts 186 FROM launches 187 JOIN launch_processes ON (launches.id = launch_processes.launch_id) 188 JOIN thread ON (launch_processes.upid = thread.upid) 189 JOIN thread_track USING (utid) 190 JOIN slice ON ( 191 slice.track_id = thread_track.id 192 AND slice.ts >= launches.ts) 193 WHERE slice.name LIKE 'reportFullyDrawn%' 194 GROUP BY launches.id 195) 196SELECT 197 launch_id, 198 report_fully_drawn_ts - launch_ts as report_fully_drawn_dur 199FROM report_fully_drawn_launch_slices; 200 201DROP VIEW IF EXISTS to_event_protos; 202CREATE VIEW to_event_protos AS 203SELECT 204 slice.name as slice_name, 205 launch_id, 206 AndroidStartupMetric_Slice( 207 'dur_ns', slice.ts - l.ts, 208 'dur_ms', (slice.ts - l.ts) / 1e6 209 ) as slice_proto 210FROM launch_main_threads l 211JOIN thread_track USING (utid) 212JOIN slice ON ( 213 slice.track_id = thread_track.id 214 AND slice.ts BETWEEN l.ts AND l.ts + l.dur); 215 216DROP VIEW IF EXISTS gc_slices; 217CREATE VIEW gc_slices AS 218 SELECT 219 slice_ts AS ts, 220 slice_dur AS dur, 221 utid, 222 launch_id 223 FROM main_process_slice_unaggregated 224 WHERE ( 225 slice_name LIKE '%mark sweep GC' 226 OR slice_name LIKE '%concurrent copying GC' 227 OR slice_name LIKE '%semispace GC'); 228 229DROP TABLE IF EXISTS gc_slices_by_state; 230CREATE VIRTUAL TABLE gc_slices_by_state 231USING SPAN_JOIN(gc_slices PARTITIONED utid, thread_state_extended PARTITIONED utid); 232 233DROP TABLE IF EXISTS gc_slices_by_state_materialized; 234CREATE TABLE gc_slices_by_state_materialized AS 235SELECT launch_id, SUM(dur) as sum_dur 236FROM gc_slices_by_state 237WHERE state = 'Running' 238GROUP BY launch_id; 239 240DROP TABLE IF EXISTS launch_threads_cpu; 241CREATE VIRTUAL TABLE launch_threads_cpu 242USING SPAN_JOIN(launch_threads PARTITIONED utid, thread_state_extended PARTITIONED utid); 243 244DROP TABLE IF EXISTS launch_threads_cpu_materialized; 245CREATE TABLE launch_threads_cpu_materialized AS 246SELECT launch_id, SUM(dur) as sum_dur 247FROM launch_threads_cpu 248WHERE thread_name = 'Jit thread pool' AND state = 'Running' 249GROUP BY launch_id; 250 251DROP TABLE IF EXISTS activity_names_materialized; 252CREATE TABLE activity_names_materialized AS 253SELECT launch_id, slice_name, slice_ts 254FROM main_process_slice_unaggregated 255WHERE (slice_name LIKE 'performResume:%' OR slice_name LIKE 'performCreate:%'); 256 257DROP TABLE IF EXISTS jit_compiled_methods_materialized; 258CREATE TABLE jit_compiled_methods_materialized AS 259SELECT 260 launch_id, 261 COUNT(1) as count 262FROM main_process_slice_unaggregated 263WHERE 264 slice_name LIKE 'JIT compiling%' 265 AND thread_name = 'Jit thread pool' 266GROUP BY launch_id; 267 268DROP TABLE IF EXISTS long_binder_transactions; 269CREATE TABLE long_binder_transactions AS 270SELECT 271 launch_id, slice_dur, thread_name 272FROM 273 main_process_slice_unaggregated 274WHERE 275 slice_name = 'binder transaction' 276 AND slice_dur >= 1e8; 277 278DROP VIEW IF EXISTS startup_view; 279CREATE VIEW startup_view AS 280SELECT 281 AndroidStartupMetric_Startup( 282 'startup_id', launches.id, 283 'package_name', launches.package, 284 'process_name', ( 285 SELECT p.name 286 FROM launch_processes lp 287 JOIN process p USING (upid) 288 WHERE lp.launch_id = launches.id 289 LIMIT 1 290 ), 291 'process', ( 292 SELECT m.metadata 293 FROM process_metadata m 294 JOIN launch_processes p USING (upid) 295 WHERE p.launch_id = launches.id 296 LIMIT 1 297 ), 298 'activities', ( 299 SELECT RepeatedField(AndroidStartupMetric_Activity( 300 'name', (SELECT STR_SPLIT(s.slice_name, ':', 1)), 301 'method', (SELECT STR_SPLIT(s.slice_name, ':', 0)), 302 'ts_method_start', s.slice_ts 303 )) 304 FROM activity_names_materialized s 305 WHERE s.launch_id = launches.id 306 ), 307 'long_binder_transactions', ( 308 SELECT RepeatedField(AndroidStartupMetric_BinderTransaction( 309 'duration', AndroidStartupMetric_Slice( 310 'dur_ns', lbt.slice_dur, 311 'dur_ms', lbt.slice_dur / 1e6 312 ), 313 'thread', lbt.thread_name 314 )) 315 FROM long_binder_transactions lbt 316 WHERE lbt.launch_id = launches.id 317 ), 318 'zygote_new_process', EXISTS(SELECT TRUE FROM zygote_forks_by_id WHERE id = launches.id), 319 'activity_hosting_process_count', ( 320 SELECT COUNT(1) FROM launch_processes p 321 WHERE p.launch_id = launches.id 322 ), 323 'event_timestamps', AndroidStartupMetric_EventTimestamps( 324 'intent_received', launches.ts, 325 'first_frame', launches.ts_end 326 ), 327 'to_first_frame', AndroidStartupMetric_ToFirstFrame( 328 'dur_ns', launches.dur, 329 'dur_ms', launches.dur / 1e6, 330 'main_thread_by_task_state', AndroidStartupMetric_TaskStateBreakdown( 331 'running_dur_ns', IFNULL( 332 ( 333 SELECT dur FROM launch_by_thread_state l 334 WHERE l.launch_id = launches.id AND state = 'Running' 335 ), 0), 336 'runnable_dur_ns', IFNULL( 337 ( 338 SELECT dur FROM launch_by_thread_state l 339 WHERE l.launch_id = launches.id AND state = 'R' 340 ), 0), 341 'uninterruptible_sleep_dur_ns', IFNULL( 342 ( 343 SELECT dur FROM launch_by_thread_state l 344 WHERE l.launch_id = launches.id AND (state = 'D' or state = 'DK') 345 ), 0), 346 'interruptible_sleep_dur_ns', IFNULL( 347 ( 348 SELECT dur FROM launch_by_thread_state l 349 WHERE l.launch_id = launches.id AND state = 'S' 350 ), 0) 351 ), 352 'mcycles_by_core_type', AndroidStartupMetric_McyclesByCoreType( 353 'little', ( 354 SELECT mcycles 355 FROM mcycles_per_core_type_per_launch m 356 WHERE m.launch_id = launches.id AND m.core_type = 'little' 357 ), 358 'big', ( 359 SELECT mcycles 360 FROM mcycles_per_core_type_per_launch m 361 WHERE m.launch_id = launches.id AND m.core_type = 'big' 362 ), 363 'bigger', ( 364 SELECT mcycles 365 FROM mcycles_per_core_type_per_launch m 366 WHERE m.launch_id = launches.id AND m.core_type = 'bigger' 367 ), 368 'unknown', ( 369 SELECT mcycles 370 FROM mcycles_per_core_type_per_launch m 371 WHERE m.launch_id = launches.id AND m.core_type = 'unknown' 372 ) 373 ), 374 'to_post_fork', ( 375 SELECT slice_proto 376 FROM to_event_protos p 377 WHERE p.launch_id = launches.id AND slice_name = 'PostFork' 378 ), 379 'to_activity_thread_main', ( 380 SELECT slice_proto 381 FROM to_event_protos p 382 WHERE p.launch_id = launches.id AND slice_name = 'ActivityThreadMain' 383 ), 384 'to_bind_application', ( 385 SELECT slice_proto 386 FROM to_event_protos p 387 WHERE p.launch_id = launches.id AND slice_name = 'bindApplication' 388 ), 389 'other_processes_spawned_count', ( 390 SELECT COUNT(1) FROM process 391 WHERE (process.name IS NULL OR process.name != launches.package) 392 AND process.start_ts BETWEEN launches.ts AND launches.ts + launches.dur 393 ), 394 'time_activity_manager', ( 395 SELECT AndroidStartupMetric_Slice( 396 'dur_ns', l.ts - launches.ts, 397 'dur_ms', (l.ts - launches.ts) / 1e6 398 ) 399 FROM launching_events l 400 WHERE l.ts BETWEEN launches.ts AND launches.ts + launches.dur 401 ), 402 'time_post_fork', ( 403 SELECT slice_proto 404 FROM main_process_slice s 405 WHERE s.launch_id = launches.id AND name = 'PostFork' 406 ), 407 'time_activity_thread_main', ( 408 SELECT slice_proto 409 FROM main_process_slice s 410 WHERE s.launch_id = launches.id AND name = 'ActivityThreadMain' 411 ), 412 'time_bind_application', ( 413 SELECT slice_proto 414 FROM main_process_slice s 415 WHERE s.launch_id = launches.id AND name = 'bindApplication' 416 ), 417 'time_activity_start', ( 418 SELECT slice_proto 419 FROM main_process_slice s 420 WHERE s.launch_id = launches.id AND name = 'activityStart' 421 ), 422 'time_activity_resume', ( 423 SELECT slice_proto 424 FROM main_process_slice s 425 WHERE s.launch_id = launches.id AND name = 'activityResume' 426 ), 427 'time_activity_restart', ( 428 SELECT slice_proto 429 FROM main_process_slice s 430 WHERE s.launch_id = launches.id AND name = 'activityRestart' 431 ), 432 'time_choreographer', ( 433 SELECT slice_proto 434 FROM main_process_slice s 435 WHERE s.launch_id = launches.id AND name LIKE 'Choreographer#doFrame%' 436 ), 437 'time_before_start_process', ( 438 SELECT AndroidStartupMetric_Slice( 439 'dur_ns', ts - launches.ts, 440 'dur_ms', (ts - launches.ts) / 1e6 441 ) 442 FROM zygote_forks_by_id z 443 WHERE z.id = launches.id 444 ), 445 'time_during_start_process', ( 446 SELECT AndroidStartupMetric_Slice( 447 'dur_ns', dur, 448 'dur_ms', dur / 1e6 449 ) 450 FROM zygote_forks_by_id z 451 WHERE z.id = launches.id 452 ), 453 'time_inflate', ( 454 SELECT slice_proto 455 FROM main_process_slice s 456 WHERE s.launch_id = launches.id AND name = 'inflate' 457 ), 458 'time_get_resources', ( 459 SELECT slice_proto 460 FROM main_process_slice s 461 WHERE s.launch_id = launches.id 462 AND name = 'ResourcesManager#getResources' 463 ), 464 'time_dex_open', ( 465 SELECT slice_proto 466 FROM main_process_slice s 467 WHERE s.launch_id = launches.id AND name = 'OpenDexFilesFromOat' 468 ), 469 'time_verify_class', ( 470 SELECT slice_proto 471 FROM main_process_slice s 472 WHERE s.launch_id = launches.id AND name = 'VerifyClass' 473 ), 474 'jit_compiled_methods', ( 475 SELECT count 476 FROM jit_compiled_methods_materialized s 477 WHERE s.launch_id = launches.id 478 ), 479 'time_jit_thread_pool_on_cpu', ( 480 SELECT 481 NULL_IF_EMPTY(AndroidStartupMetric_Slice( 482 'dur_ns', sum_dur, 483 'dur_ms', sum_dur / 1e6 484 )) 485 FROM launch_threads_cpu_materialized 486 WHERE launch_id = launches.id 487 ), 488 'time_gc_total', ( 489 SELECT slice_proto 490 FROM main_process_slice s 491 WHERE s.launch_id = launches.id AND name = 'GC' 492 ), 493 'time_gc_on_cpu', ( 494 SELECT 495 NULL_IF_EMPTY(AndroidStartupMetric_Slice( 496 'dur_ns', sum_dur, 497 'dur_ms', sum_dur / 1e6 498 )) 499 FROM gc_slices_by_state_materialized 500 WHERE launch_id = launches.id 501 ) 502 ), 503 'hsc', ( 504 SELECT NULL_IF_EMPTY(AndroidStartupMetric_HscMetrics( 505 'full_startup', ( 506 SELECT AndroidStartupMetric_Slice( 507 'dur_ns', h.ts_total, 508 'dur_ms', h.ts_total / 1e6 509 ) 510 FROM hsc_based_startup_times h 511 WHERE h.id = launches.id 512 ) 513 )) 514 ), 515 'report_fully_drawn', ( 516 SELECT NULL_IF_EMPTY(AndroidStartupMetric_Slice( 517 'dur_ns', report_fully_drawn_dur, 518 'dur_ms', report_fully_drawn_dur / 1e6 519 )) 520 FROM report_fully_drawn_per_launch r 521 WHERE r.launch_id = launches.id 522 ), 523 'optimization_status',( 524 SELECT RepeatedField(AndroidStartupMetric_OptimizationStatus( 525 'location', SUBSTR(STR_SPLIT(name, ' status=', 0), LENGTH('location=') + 1), 526 'odex_status', STR_SPLIT(STR_SPLIT(name, ' status=', 1), ' filter=', 0), 527 'compilation_filter', STR_SPLIT(STR_SPLIT(name, ' filter=', 1), ' reason=', 0), 528 'compilation_reason', STR_SPLIT(name, ' reason=', 1) 529 )) 530 FROM main_process_slice s 531 WHERE name LIKE 'location=% status=% filter=% reason=%' 532 ) 533 ) as startup 534FROM launches; 535 536DROP VIEW IF EXISTS android_startup_event; 537CREATE VIEW android_startup_event AS 538SELECT 539 'slice' as track_type, 540 'Android App Startups' as track_name, 541 l.ts as ts, 542 l.dur as dur, 543 l.package as slice_name 544FROM launches l; 545 546DROP VIEW IF EXISTS android_startup_output; 547CREATE VIEW android_startup_output AS 548SELECT 549 AndroidStartupMetric( 550 'startup', ( 551 SELECT RepeatedField(startup) FROM startup_view 552 ) 553 ); 554