• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2024 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_frame_boundary`,
19-- containing bounds of frames within 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;
25INCLUDE PERFETTO MODULE android.frames.timeline;
26
27-- TODO(b/296349525): Add this to the perfetto standard library.
28DROP TABLE IF EXISTS android_cujs;
29CREATE TABLE android_cujs AS
30    SELECT
31        cuj_id,
32        cuj.upid,
33        t.utid AS ui_thread,
34        process_name,
35        process_metadata,
36        cuj_name,
37        cuj.layer_id,
38        tb.ts,
39        tb.dur,
40        tb.ts_end,
41        begin_vsync,
42        end_vsync
43    FROM android_jank_cuj_main_thread_cuj_boundary tb
44    JOIN android_jank_cuj cuj USING (cuj_id)
45    JOIN android_jank_cuj_main_thread t USING (cuj_id);
46
47-- While calculating the metric, there are two possibilities for a blocking call:
48-- 1. Blocking call is completely within a frame boundary.
49-- 2. Blocking call crosses the frame boundary into the next frame.
50-- For the first case, the blocking call duration is the 'dur' field value itself. But for the
51-- second case, only the part within the frame is considered.
52DROP TABLE IF EXISTS blocking_calls_per_frame;
53CREATE PERFETTO TABLE blocking_calls_per_frame AS
54SELECT
55    MIN(
56        bc.dur,
57        frame.ts_end - bc.ts,
58        bc.ts_end - frame.ts
59    ) AS dur,
60    MAX(frame.ts, bc.ts) AS ts,
61    bc.upid,
62    bc.name,
63    bc.process_name,
64    bc.utid,
65    frame.frame_id,
66    frame.layer_id
67FROM _android_critical_blocking_calls bc
68JOIN android_frames_layers frame
69ON bc.utid = frame.ui_thread_utid
70   -- The following condition to accommodate blocking call crossing frame boundary. The blocking
71   -- call starts in a frame and ends in a frame. It can either be the same frame or a different
72   -- frame.
73WHERE (bc.ts >= frame.ts AND bc.ts <= frame.ts_end) -- Blocking call starts within the frame.
74    OR (bc.ts_end >= frame.ts AND bc.ts_end <= frame.ts_end); -- Blocking call ends within the frame.
75
76-- Table capturing the full and partial frames within a CUJ boundary. This table captures the
77-- layer ID associated with the actual frame too.
78DROP TABLE IF EXISTS frames_in_cuj;
79CREATE PERFETTO TABLE frames_in_cuj AS
80SELECT
81    cuj.cuj_name,
82    cuj.upid,
83    cuj.process_name,
84    frame.layer_id,
85    frame.frame_id,
86    cuj.cuj_id,
87    MAX(frame.ts, cuj.ts) AS frame_ts,
88    MIN(
89        frame.dur,
90        cuj.ts_end - frame.ts,
91        frame.ts_end - cuj.ts
92    ) AS dur
93FROM android_frames_layers frame
94JOIN android_cujs cuj
95ON frame.upid = cuj.upid
96   AND frame.layer_id = cuj.layer_id
97   AND frame.ui_thread_utid = cuj.ui_thread
98-- Check whether the frame_id falls within the begin and end vsync of the cuj.
99-- Also check if the frame start or end timestamp falls within the cuj boundary.
100WHERE
101   -- frame withtin cuj vsync boundary
102   frame_id >= begin_vsync AND frame_id <= end_vsync
103   AND (
104      -- frame start within cuj
105      (frame.ts >= cuj.ts AND frame.ts <= cuj.ts_end)
106      OR
107      -- frame end within cuj
108      (frame.ts_end >= cuj.ts AND frame.ts_end <= cuj.ts_end)
109   );
110
111-- Combine the above two tables to get blocking calls within frame within CUJ.
112DROP TABLE IF EXISTS blocking_calls_frame_cuj;
113CREATE PERFETTO TABLE blocking_calls_frame_cuj AS
114SELECT
115    b.upid,
116    b.frame_id,
117    b.layer_id,
118    b.name,
119    frame_cuj.cuj_name,
120    b.ts,
121    b.dur,
122    b.process_name
123FROM frames_in_cuj frame_cuj
124JOIN blocking_calls_per_frame b
125USING (upid, frame_id, layer_id);
126
127-- Calculate the mean/max values for duration and count for blocking calls per frame.
128DROP TABLE IF EXISTS android_blocking_calls_cuj_per_frame_calls;
129CREATE PERFETTO TABLE android_blocking_calls_cuj_per_frame_calls AS
130WITH blocking_calls_aggregate_values AS (
131  -- Aggregate the count and sum for each blocking call by grouping on CUJ name, blocking
132  -- call name and frame ID(vsync).
133  SELECT
134    COUNT(*) AS cnt,
135    SUM(dur) AS total_dur_per_frame_ns,
136    MAX(dur) AS max_dur_per_frame_ns,
137    cuj_name,
138    upid,
139    process_name,
140    name
141  FROM blocking_calls_frame_cuj
142  GROUP BY cuj_name, name, frame_id
143),
144frame_cnt_per_cuj AS (
145  -- Calculate the total number of frames for all CUJs across all instances(eg. multiple
146  -- instances for the same CUJ).
147  SELECT
148    COUNT(*) AS frame_cnt,
149    cuj_name
150  FROM frames_in_cuj
151  GROUP BY cuj_name
152)
153SELECT
154    cast_double!(SUM(cnt)) / frame_cnt AS mean_cnt_per_frame,
155    MAX(cnt) AS max_cnt_per_frame,
156    SUM(total_dur_per_frame_ns) / frame_cnt AS mean_dur_per_frame_ns,
157    MAX(max_dur_per_frame_ns) AS max_dur_per_frame_ns,
158    name,
159    upid,
160    bc.cuj_name,
161    process_name
162FROM blocking_calls_aggregate_values bc
163JOIN frame_cnt_per_cuj fc
164USING(cuj_name)
165GROUP BY bc.cuj_name, name;
166
167DROP VIEW IF EXISTS android_blocking_calls_cuj_per_frame_metric_output;
168CREATE PERFETTO VIEW android_blocking_calls_cuj_per_frame_metric_output AS
169SELECT AndroidCujBlockingCallsPerFrameMetric('cuj', (
170    SELECT RepeatedField(
171        AndroidCujBlockingCallsPerFrameMetric_Cuj(
172            'name', cuj_name,
173            'process', process_metadata,
174            'blocking_calls', (
175                SELECT RepeatedField(
176                    AndroidBlockingCallPerFrame(
177                        'name', b.name,
178                        'max_dur_per_frame_ms', CAST(max_dur_per_frame_ns / 1e6 AS INT),
179                        'max_dur_per_frame_ns', b.max_dur_per_frame_ns,
180                        'mean_dur_per_frame_ms', CAST(mean_dur_per_frame_ns / 1e6 AS INT),
181                        'mean_dur_per_frame_ns', b.mean_dur_per_frame_ns,
182                        'max_cnt_per_frame', CAST(b.max_cnt_per_frame AS INT),
183                        'mean_cnt_per_frame', b.mean_cnt_per_frame
184                    )
185                )
186                FROM android_blocking_calls_cuj_per_frame_calls b
187                WHERE b.cuj_name = cuj.cuj_name and b.upid = cuj.upid
188                GROUP BY b.cuj_name
189            )
190        )
191    )
192    FROM (SELECT DISTINCT cuj_name, upid, process_metadata FROM android_cujs) cuj
193));
194