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