• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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