• 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        process.name AS process_name,
36        process_metadata.metadata AS process_metadata,
37        -- Extracts "CUJ_NAME" from "L<CUJ_NAME>"
38        SUBSTR(slice.name, 3, LENGTH(slice.name) - 3) AS cuj_name,
39        ts,
40        dur,
41        ts + dur AS ts_end,
42        'completed' AS state
43    FROM slice
44        JOIN process_track
45          ON slice.track_id = process_track.id
46        JOIN process USING (upid)
47        JOIN process_metadata USING (upid)
48    WHERE
49        slice.name GLOB 'L<*>'
50    AND dur > 0
51),
52all_cujs AS (
53    SELECT
54        cuj_id,
55        upid,
56        process_name,
57        process_metadata,
58        cuj_name,
59        tb.ts,
60        tb.dur,
61        tb.ts_end
62    FROM android_jank_cuj_main_thread_cuj_boundary tb
63        JOIN android_jank_cuj using (cuj_id)
64UNION
65    SELECT
66        cuj_id,
67        upid,
68        process_name,
69        process_metadata,
70        cuj_name,
71        ts,
72        dur,
73        ts_end
74    FROM latency_cujs
75)
76SELECT ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, *
77FROM all_cujs;
78
79-- We have:
80--  (1) a list of slices from the main thread of each process from the
81--  all_main_thread_relevant_slices table.
82--  (2) a list of android cuj with beginning, end, and process
83-- It's needed to:
84--  (1) assign a cuj to each slice. If there are multiple cujs going on during a
85--      slice, there needs to be 2 entries for that slice, one for each cuj id.
86--  (2) each slice needs to be trimmed to be fully inside the cuj associated
87--      (as we don't care about what's outside cujs)
88DROP TABLE IF EXISTS android_blocking_calls_cuj_calls;
89CREATE TABLE android_blocking_calls_cuj_calls AS
90WITH
91main_thread_slices_scoped_to_cujs AS (
92SELECT
93    s.id,
94    s.id AS slice_id,
95    s.name,
96    max(s.ts, cuj.ts) AS ts,
97    min(s.ts + s.dur, cuj.ts_end) as ts_end,
98    min(s.ts + s.dur, cuj.ts_end) - max(s.ts, cuj.ts) AS dur,
99    cuj.cuj_id,
100    cuj.cuj_name,
101    s.process_name,
102    s.upid,
103    s.utid
104FROM _android_critical_blocking_calls s
105    JOIN  android_cujs cuj
106    -- only when there is an overlap
107    ON s.ts + s.dur > cuj.ts AND s.ts < cuj.ts_end
108        -- and are from the same process
109        AND s.upid = cuj.upid
110)
111SELECT
112    name,
113    COUNT(*) AS occurrences,
114    MAX(dur) AS max_dur_ns,
115    MIN(dur) AS min_dur_ns,
116    SUM(dur) AS total_dur_ns,
117    upid,
118    cuj_id,
119    cuj_name,
120    process_name
121FROM
122    main_thread_slices_scoped_to_cujs
123GROUP BY name, upid, cuj_id, cuj_name, process_name
124ORDER BY cuj_id;
125
126
127DROP VIEW IF EXISTS android_blocking_calls_cuj_metric_output;
128CREATE PERFETTO VIEW android_blocking_calls_cuj_metric_output AS
129SELECT AndroidBlockingCallsCujMetric('cuj', (
130    SELECT RepeatedField(
131        AndroidBlockingCallsCujMetric_Cuj(
132            'id', cuj_id,
133            'name', cuj_name,
134            'process', process_metadata,
135            'ts',  cuj.ts,
136            'dur', cuj.dur,
137            'blocking_calls', (
138                SELECT RepeatedField(
139                    AndroidBlockingCall(
140                        'name', b.name,
141                        'cnt', b.occurrences,
142                        'total_dur_ms', CAST(total_dur_ns / 1e6 AS INT),
143                        'max_dur_ms', CAST(max_dur_ns / 1e6 AS INT),
144                        'min_dur_ms', CAST(min_dur_ns / 1e6 AS INT),
145                        'total_dur_ns', b.total_dur_ns,
146                        'max_dur_ns', b.max_dur_ns,
147                        'min_dur_ns', b.min_dur_ns
148                    )
149                )
150                FROM android_blocking_calls_cuj_calls b
151                WHERE b.cuj_id = cuj.cuj_id and b.upid = cuj.upid
152                ORDER BY total_dur_ns DESC
153            )
154        )
155    )
156    FROM android_cujs cuj
157    ORDER BY cuj.cuj_id ASC
158));
159