• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2023 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-- Create the base table (`android_jank_cuj`) containing all completed CUJs
17-- found in the trace.
18-- This script will use the `android_jank_cuj_main_thread_cuj_boundary`,
19-- containing bounds of jank CUJs.
20SELECT RUN_METRIC('android/android_jank_cuj.sql');
21
22INCLUDE PERFETTO MODULE android.slices;
23INCLUDE PERFETTO MODULE android.binder;
24INCLUDE PERFETTO MODULE android.critical_blocking_calls;
25
26-- Jank "J<*>" and latency "L<*>" cujs are put together in android_cujs table.
27-- They are computed separately as latency ones are slightly different, don't
28-- currently have the same way to be cancelled, and are not anchored to vsyncs.
29DROP TABLE IF EXISTS android_cujs;
30CREATE TABLE android_cujs AS
31WITH latency_cujs AS (
32    SELECT
33        ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id,
34        process.upid AS upid,
35        -- Latency CUJs don't have a well defined thread. Let's always consider
36        -- the app main thread for those.
37        process.upid AS utid,
38        process.name AS process_name,
39        process_metadata.metadata AS process_metadata,
40        -- Extracts "CUJ_NAME" from "L<CUJ_NAME>"
41        SUBSTR(slice.name, 3, LENGTH(slice.name) - 3) AS cuj_name,
42        ts,
43        dur,
44        ts + dur AS ts_end,
45        'completed' AS state
46    FROM slice
47        JOIN process_track
48          ON slice.track_id = process_track.id
49        JOIN process USING (upid)
50        JOIN process_metadata USING (upid)
51    WHERE
52        slice.name GLOB 'L<*>'
53    AND dur > 0
54),
55all_cujs AS (
56    SELECT
57        cuj_id,
58        cuj.upid,
59        t.utid as ui_thread,
60        process_name,
61        process_metadata,
62        cuj_name,
63        tb.ts,
64        tb.dur,
65        tb.ts_end
66    FROM android_jank_cuj_main_thread_cuj_boundary tb
67        JOIN android_jank_cuj cuj USING (cuj_id)
68        JOIN android_jank_cuj_main_thread t USING (cuj_id)
69UNION
70    SELECT
71        cuj_id,
72        upid,
73        utid as ui_thread,
74        process_name,
75        process_metadata,
76        cuj_name,
77        ts,
78        dur,
79        ts_end
80    FROM latency_cujs
81)
82SELECT ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, *
83FROM all_cujs;
84
85-- We have:
86--  (1) a list of slices from the main thread of each process from the
87--  all_main_thread_relevant_slices table.
88--  (2) a list of android cuj with beginning, end, and process
89-- It's needed to:
90--  (1) assign a cuj to each slice. If there are multiple cujs going on during a
91--      slice, there needs to be 2 entries for that slice, one for each cuj id.
92--  (2) each slice needs to be trimmed to be fully inside the cuj associated
93--      (as we don't care about what's outside cujs)
94DROP TABLE IF EXISTS main_thread_slices_scoped_to_cujs;
95CREATE PERFETTO TABLE main_thread_slices_scoped_to_cujs AS
96SELECT
97    s.id,
98    s.id AS slice_id,
99    s.name,
100    max(s.ts, cuj.ts) AS ts,
101    min(s.ts + s.dur, cuj.ts_end) as ts_end,
102    min(s.ts + s.dur, cuj.ts_end) - max(s.ts, cuj.ts) AS dur,
103    cuj.cuj_id,
104    cuj.cuj_name,
105    s.process_name,
106    s.upid,
107    s.utid
108FROM _android_critical_blocking_calls s
109    JOIN  android_cujs cuj
110    -- only when there is an overlap
111    ON s.ts + s.dur > cuj.ts AND s.ts < cuj.ts_end
112        -- and are from the same process
113        AND s.upid = cuj.upid
114        -- from the CUJ ui thread only
115        AND s.utid = cuj.ui_thread;
116
117
118DROP TABLE IF EXISTS android_blocking_calls_cuj_calls;
119CREATE TABLE android_blocking_calls_cuj_calls AS
120SELECT
121    name,
122    COUNT(*) AS occurrences,
123    MAX(dur) AS max_dur_ns,
124    MIN(dur) AS min_dur_ns,
125    SUM(dur) AS total_dur_ns,
126    upid,
127    cuj_id,
128    cuj_name,
129    process_name
130FROM
131    main_thread_slices_scoped_to_cujs
132GROUP BY name, upid, cuj_id, cuj_name, process_name
133ORDER BY cuj_id;
134
135
136DROP VIEW IF EXISTS android_blocking_calls_cuj_metric_output;
137CREATE PERFETTO VIEW android_blocking_calls_cuj_metric_output AS
138SELECT AndroidBlockingCallsCujMetric('cuj', (
139    SELECT RepeatedField(
140        AndroidBlockingCallsCujMetric_Cuj(
141            'id', cuj_id,
142            'name', cuj_name,
143            'process', process_metadata,
144            'ts',  cuj.ts,
145            'dur', cuj.dur,
146            'blocking_calls', (
147                SELECT RepeatedField(
148                    AndroidBlockingCall(
149                        'name', b.name,
150                        'cnt', b.occurrences,
151                        'total_dur_ms', CAST(total_dur_ns / 1e6 AS INT),
152                        'max_dur_ms', CAST(max_dur_ns / 1e6 AS INT),
153                        'min_dur_ms', CAST(min_dur_ns / 1e6 AS INT),
154                        'total_dur_ns', b.total_dur_ns,
155                        'max_dur_ns', b.max_dur_ns,
156                        'min_dur_ns', b.min_dur_ns
157                    )
158                )
159                FROM android_blocking_calls_cuj_calls b
160                WHERE b.cuj_id = cuj.cuj_id and b.upid = cuj.upid
161                ORDER BY total_dur_ns DESC
162            )
163        )
164    )
165    FROM android_cujs cuj
166    ORDER BY cuj.cuj_id ASC
167));
168