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 16INCLUDE PERFETTO MODULE slices.with_context; 17 18INCLUDE PERFETTO MODULE android.frames.timeline_maxsdk28; 19 20-- Parses the slice name to fetch `frame_id` from `slice` table. 21-- Use with caution. Slice names are a flaky source of ids and the resulting 22-- table might require some further operations. 23CREATE PERFETTO FUNCTION _get_frame_table_with_id( 24 -- String just before id. 25 glob_str STRING 26) 27RETURNS TABLE ( 28 -- Frame slice. 29 id ID(slice.id), 30 -- Parsed frame id. 31 frame_id LONG, 32 -- Utid. 33 utid JOINID(thread.id), 34 -- Upid. 35 upid JOINID(process.id), 36 -- Timestamp of the frame slice. 37 ts TIMESTAMP 38) AS 39WITH 40 all_found AS ( 41 SELECT 42 id, 43 cast_int!(STR_SPLIT(name, ' ', 1)) AS frame_id, 44 utid, 45 upid, 46 ts 47 FROM thread_slice 48 -- Mostly the frame slice is at depth 0. Though it could be pushed to depth 1 while users 49 -- enable low layer trace e.g. atrace_app. 50 WHERE 51 name GLOB $glob_str AND depth IN (0, 1) 52 ) 53SELECT 54 * 55FROM all_found 56-- Casting string to int returns 0 if the string can't be cast. 57WHERE 58 frame_id != 0; 59 60-- All of the `Choreographer#doFrame` slices with their frame id. 61CREATE PERFETTO TABLE android_frames_choreographer_do_frame ( 62 -- Choreographer#doFrame slice. Slice with the name "Choreographer#doFrame 63 -- {frame id}". 64 id ID(slice.id), 65 -- Frame id. Taken as the value behind "Choreographer#doFrame" in slice 66 -- name. 67 frame_id LONG, 68 -- Utid of the UI thread 69 ui_thread_utid JOINID(thread.id), 70 -- Upid of application process 71 upid JOINID(process.id), 72 -- Timestamp of the slice. 73 ts TIMESTAMP 74) AS 75SELECT 76 id, 77 frame_id, 78 utid AS ui_thread_utid, 79 upid, 80 ts 81-- Some OEMs have customized `doFrame` to add more information, but we've only 82-- observed it added after the frame ID (b/303823815). 83FROM _get_frame_table_with_id('Choreographer#doFrame*'); 84 85-- All of the `DrawFrame` slices with their frame id and render thread. 86-- There might be multiple DrawFrames slices for a single vsync (frame id). 87-- This happens when we are drawing multiple layers (e.g. status bar and 88-- notifications). 89CREATE PERFETTO TABLE android_frames_draw_frame ( 90 -- DrawFrame slice. Slice with the name "DrawFrame {frame id}". 91 id ID(slice.id), 92 -- Frame id. Taken as the value behind "DrawFrame" in slice 93 -- name. 94 frame_id LONG, 95 -- Utid of the render thread 96 render_thread_utid JOINID(thread.id), 97 -- Upid of application process 98 upid JOINID(process.id) 99) AS 100SELECT 101 id, 102 frame_id, 103 utid AS render_thread_utid, 104 upid 105FROM _get_frame_table_with_id('DrawFrame*'); 106 107-- Fetch distinct actual frames per layer per process. 108CREATE PERFETTO TABLE _distinct_layer_actual_timeline_slice_per_process AS 109SELECT 110 cast_int!(name) AS frame_id, 111 CAST(str_split(layer_name, '#', 1) AS INTEGER) AS layer_id, 112 layer_name, 113 id AS slice_id, 114 ts, 115 dur, 116 upid 117FROM actual_frame_timeline_slice; 118 119-- Fetch distinct expected frames per process. 120CREATE PERFETTO TABLE _distinct_from_expected_timeline_slice_per_process AS 121SELECT 122 cast_int!(name) AS frame_id, 123 upid, 124 id 125FROM expected_frame_timeline_slice; 126 127-- TODO(b/384322064) Match actual timeline slice with correct draw frame using layer name. 128-- All slices related to one frame. Aggregates `Choreographer#doFrame`, 129-- `actual_frame_timeline_slice` and `expected_frame_timeline_slice` slices. 130-- This table differs slightly from the android_frames table, as it 131-- captures the layer_id for each actual timeline slice too. 132CREATE PERFETTO TABLE android_frames_layers ( 133 -- Frame id. 134 frame_id LONG, 135 -- Timestamp of the frame. Start of the frame as defined by the start of 136 -- "Choreographer#doFrame" slice and the same as the start of the frame in 137 -- `actual_frame_timeline_slice if present. 138 ts TIMESTAMP, 139 -- Duration of the frame, as defined by the duration of the corresponding 140 -- `actual_frame_timeline_slice` or, if not present the time between the 141 -- `ts` and the end of the final `DrawFrame`. 142 dur DURATION, 143 -- End timestamp of the frame. End of the frame as defined by the sum of start timestamp and 144 -- duration of the frame. 145 ts_end TIMESTAMP, 146 -- `slice.id` of "Choreographer#doFrame" slice. 147 do_frame_id JOINID(slice.id), 148 -- `slice.id` of "DrawFrame" slice. For now, we only support the first 149 -- DrawFrame slice (due to b/384322064). 150 draw_frame_id JOINID(slice.id), 151 -- `slice.id` from `actual_frame_timeline_slice` 152 actual_frame_timeline_id JOINID(slice.id), 153 -- `slice.id` from `expected_frame_timeline_slice` 154 expected_frame_timeline_id JOINID(slice.id), 155 -- `utid` of the render thread. 156 render_thread_utid JOINID(thread.id), 157 -- thread id of the UI thread. 158 ui_thread_utid JOINID(thread.id), 159 -- layer id associated with the actual frame. 160 layer_id LONG, 161 -- layer name associated with the actual frame. 162 layer_name STRING, 163 -- process id. 164 upid JOINID(process.id), 165 -- process name. 166 process_name STRING 167) AS 168WITH 169 fallback AS MATERIALIZED ( 170 SELECT 171 frame_id, 172 do_frame_slice.ts AS ts, 173 ( 174 draw_frame_slice.ts + draw_frame_slice.dur 175 ) - do_frame_slice.ts AS dur 176 FROM android_frames_choreographer_do_frame AS do_frame 177 JOIN android_frames_draw_frame AS draw_frame 178 USING (frame_id, upid) 179 JOIN slice AS do_frame_slice 180 ON ( 181 do_frame.id = do_frame_slice.id 182 ) 183 JOIN slice AS draw_frame_slice 184 ON ( 185 draw_frame.id = draw_frame_slice.id 186 ) 187 ), 188 frames_sdk_after_28 AS ( 189 SELECT 190 frame_id, 191 coalesce(act.ts, fallback.ts) AS ts, 192 coalesce(act.dur, fallback.dur) AS dur, 193 do_frame.id AS do_frame_id, 194 draw_frame.id AS draw_frame_id, 195 draw_frame.render_thread_utid, 196 do_frame.ui_thread_utid AS ui_thread_utid, 197 exp.upid AS upid, 198 process.name AS process_name, 199 "after_28" AS sdk, 200 act.slice_id AS actual_frame_timeline_id, 201 exp.id AS expected_frame_timeline_id, 202 act.layer_id AS layer_id, 203 act.layer_name AS layer_name 204 FROM android_frames_choreographer_do_frame AS do_frame 205 JOIN android_frames_draw_frame AS draw_frame 206 USING (frame_id, upid) 207 JOIN fallback 208 USING (frame_id) 209 JOIN process 210 USING (upid) 211 LEFT JOIN _distinct_layer_actual_timeline_slice_per_process AS act 212 USING (frame_id, upid) 213 LEFT JOIN _distinct_from_expected_timeline_slice_per_process AS exp 214 USING (frame_id, upid) 215 ORDER BY 216 frame_id 217 ), 218 all_frames AS ( 219 SELECT 220 * 221 FROM frames_sdk_after_28 222 UNION 223 SELECT 224 *, 225 NULL AS actual_frame_timeline_id, 226 NULL AS expected_frame_timeline_id, 227 NULL AS layer_id, 228 NULL AS layer_name 229 FROM _frames_maxsdk_28 230 ) 231SELECT 232 frame_id, 233 ts, 234 dur, 235 ( 236 ts + dur 237 ) AS ts_end, 238 do_frame_id, 239 draw_frame_id, 240 actual_frame_timeline_id, 241 expected_frame_timeline_id, 242 render_thread_utid, 243 ui_thread_utid, 244 layer_id, 245 layer_name, 246 upid, 247 process_name 248FROM all_frames 249WHERE 250 sdk = iif( 251 ( 252 SELECT 253 count(1) 254 FROM actual_frame_timeline_slice 255 ) > 0, 256 "after_28", 257 "maxsdk28" 258 ); 259 260-- Table based on the android_frames_layers table. It aggregates time, duration and counts 261-- information across different layers for a given frame_id in a given process. 262CREATE PERFETTO TABLE android_frames ( 263 -- Frame id. 264 frame_id LONG, 265 -- Timestamp of the frame. Start of the frame as defined by the start of 266 -- "Choreographer#doFrame" slice and the same as the start of the frame in 267 -- `actual_frame_timeline_slice if present. 268 ts TIMESTAMP, 269 -- Duration of the frame, as defined by the duration of the corresponding 270 -- `actual_frame_timeline_slice` or, if not present the time between the 271 -- `ts` and the end of the final `DrawFrame`. 272 dur DURATION, 273 -- `slice.id` of "Choreographer#doFrame" slice. 274 do_frame_id JOINID(slice.id), 275 -- `slice.id` of "DrawFrame" slice. For now, we only support the first 276 -- DrawFrame slice (due to b/384322064). 277 draw_frame_id JOINID(slice.id), 278 -- `slice.id` from `actual_frame_timeline_slice` 279 actual_frame_timeline_id JOINID(slice.id), 280 -- `slice.id` from `expected_frame_timeline_slice` 281 expected_frame_timeline_id JOINID(slice.id), 282 -- `utid` of the render thread. 283 render_thread_utid JOINID(thread.id), 284 -- thread id of the UI thread. 285 ui_thread_utid JOINID(thread.id), 286 -- Count of slices in `actual_frame_timeline_slice` related to this frame. 287 actual_frame_timeline_count LONG, 288 -- Count of slices in `expected_frame_timeline_slice` related to this frame. 289 expected_frame_timeline_count LONG, 290 -- Count of draw_frame associated to this frame. 291 draw_frame_count LONG, 292 -- process id. 293 upid JOINID(process.id), 294 -- process name. 295 process_name STRING 296) AS 297SELECT 298 frame_id, 299 min(frames_layers.ts) AS ts, 300 max(frames_layers.dur) AS dur, 301 min(do_frame_id) AS do_frame_id, 302 min(draw_frame_id) AS draw_frame_id, 303 min(actual_frame_timeline_id) AS actual_frame_timeline_id, 304 expected_frame_timeline_id, 305 render_thread_utid, 306 ui_thread_utid, 307 count(DISTINCT actual_frame_timeline_id) AS actual_frame_timeline_count, 308 -- Expected frame count will always be 1 for a given frame_id. 309 1 AS expected_frame_timeline_count, 310 count(DISTINCT draw_frame_id) AS draw_frame_count, 311 upid, 312 process_name 313FROM android_frames_layers AS frames_layers 314GROUP BY 315 frame_id, 316 upid; 317 318-- Returns first frame after the provided timestamp. The returning table has at 319-- most one row. 320CREATE PERFETTO FUNCTION android_first_frame_after( 321 -- Timestamp. 322 ts TIMESTAMP 323) 324RETURNS TABLE ( 325 -- Frame id. 326 frame_id LONG, 327 -- Start of the frame, the timestamp of the "Choreographer#doFrame" slice. 328 ts TIMESTAMP, 329 -- Duration of the frame. 330 dur DURATION, 331 -- "Choreographer#doFrame" slice. The slice with name 332 -- "Choreographer#doFrame" corresponding to this frame. 333 do_frame_id JOINID(slice.id), 334 -- "DrawFrame" slice. The slice with name "DrawFrame" corresponding to this 335 -- frame. 336 draw_frame_id JOINID(slice.id), 337 -- actual_frame_timeline_slice` slice related to this frame. 338 actual_frame_timeline_id JOINID(slice.id), 339 -- `expected_frame_timeline_slice` slice related to this frame. 340 expected_frame_timeline_id JOINID(slice.id), 341 -- `utid` of the render thread. 342 render_thread_utid JOINID(thread.id), 343 -- `utid` of the UI thread. 344 ui_thread_utid JOINID(thread.id) 345) AS 346SELECT 347 frame_id, 348 ts, 349 dur, 350 do_frame_id, 351 draw_frame_id, 352 actual_frame_timeline_id, 353 expected_frame_timeline_id, 354 render_thread_utid, 355 ui_thread_utid 356FROM android_frames 357WHERE 358 ts > $ts 359ORDER BY 360 ts 361LIMIT 1; 362