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; 17INCLUDE PERFETTO MODULE android.frames.timeline_maxsdk28; 18 19-- Parses the slice name to fetch `frame_id` from `slice` table. 20-- Use with caution. Slice names are a flaky source of ids and the resulting 21-- table might require some further operations. 22CREATE PERFETTO FUNCTION _get_frame_table_with_id( 23 -- String just before id. 24 glob_str STRING 25) RETURNS TABLE ( 26 -- `slice.id` of the frame slice. 27 id INT, 28 -- Parsed frame id. 29 frame_id INT, 30 -- Utid. 31 utid INT, 32 -- Upid. 33 upid INT 34) AS 35WITH all_found AS ( 36 SELECT 37 id, 38 cast_int!(STR_SPLIT(name, ' ', 1)) AS frame_id, 39 utid, 40 upid 41 FROM thread_slice 42 WHERE name GLOB $glob_str AND depth = 0 43) 44SELECT * 45FROM all_found 46-- Casting string to int returns 0 if the string can't be cast. 47WHERE frame_id != 0; 48 49-- All of the `Choreographer#doFrame` slices with their frame id. 50CREATE PERFETTO TABLE android_frames_choreographer_do_frame( 51 -- `slice.id` 52 id INT, 53 -- Frame id 54 frame_id INT, 55 -- Utid of the UI thread 56 ui_thread_utid INT, 57 -- Upid of application process 58 upid INT 59) AS 60SELECT 61 id, 62 frame_id, 63 utid AS ui_thread_utid, 64 upid 65-- Some OEMs have customized `doFrame` to add more information, but we've only 66-- observed it added after the frame ID (b/303823815). 67FROM _get_frame_table_with_id('Choreographer#doFrame*'); 68 69-- All of the `DrawFrame` slices with their frame id and render thread. 70-- There might be multiple DrawFrames slices for a single vsync (frame id). 71-- This happens when we are drawing multiple layers (e.g. status bar and 72-- notifications). 73CREATE PERFETTO TABLE android_frames_draw_frame( 74 -- `slice.id` 75 id INT, 76 -- Frame id 77 frame_id INT, 78 -- Utid of the render thread 79 render_thread_utid INT, 80 -- Upid of application process 81 upid INT 82) AS 83SELECT 84 id, 85 frame_id, 86 utid AS render_thread_utid, 87 upid 88FROM _get_frame_table_with_id('DrawFrame*'); 89 90-- `actual_frame_timeline_slice` returns the same slice on different tracks. 91-- We are getting the first slice with one frame id. 92CREATE PERFETTO TABLE _distinct_from_actual_timeline_slice AS 93SELECT 94 id, 95 cast_int!(name) AS frame_id, 96 ts, 97 dur 98FROM actual_frame_timeline_slice 99GROUP BY 2; 100 101-- `expected_frame_timeline_slice` returns the same slice on different tracks. 102-- We are getting the first slice with one frame id. 103CREATE PERFETTO TABLE _distinct_from_expected_timeline_slice AS 104SELECT 105 id, 106 cast_int!(name) AS frame_id 107FROM expected_frame_timeline_slice 108GROUP BY 2; 109 110-- All slices related to one frame. Aggregates `Choreographer#doFrame`, 111-- `DrawFrame`, `actual_frame_timeline_slice` and 112-- `expected_frame_timeline_slice` slices. 113-- See https://perfetto.dev/docs/data-sources/frametimeline for details. 114CREATE PERFETTO TABLE android_frames( 115 -- Frame id. 116 frame_id INT, 117 -- Timestamp of the frame. Start of the frame as defined by the start of 118 -- "Choreographer#doFrame" slice and the same as the start of the frame in 119 -- `actual_frame_timeline_slice if present. 120 ts INT, 121 -- Duration of the frame, as defined by the duration of the corresponding 122 -- `actual_frame_timeline_slice` or, if not present the time between the 123 -- `ts` and the end of the final `DrawFrame`. 124 dur INT, 125 -- `slice.id` of "Choreographer#doFrame" slice. 126 do_frame_id INT, 127 -- `slice.id` of "DrawFrame" slice. 128 draw_frame_id INT, 129 -- `slice.id` from `actual_frame_timeline_slice` 130 actual_frame_timeline_id INT, 131 -- `slice.id` from `expected_frame_timeline_slice` 132 expected_frame_timeline_id INT, 133 -- `utid` of the render thread. 134 render_thread_utid INT, 135 -- `utid` of the UI thread. 136 ui_thread_utid INT 137) AS 138WITH fallback AS MATERIALIZED ( 139 SELECT 140 frame_id, 141 do_frame_slice.ts AS ts, 142 MAX(draw_frame_slice.ts + draw_frame_slice.dur) - do_frame_slice.ts AS dur 143 FROM android_frames_choreographer_do_frame do_frame 144 JOIN android_frames_draw_frame draw_frame USING (frame_id, upid) 145 JOIN slice do_frame_slice ON (do_frame.id = do_frame_slice.id) 146 JOIN slice draw_frame_slice ON (draw_frame.id = draw_frame_slice.id) 147GROUP BY 1 148), 149frames_sdk_after_28 AS ( 150SELECT 151 frame_id, 152 COALESCE(act.ts, fallback.ts) AS ts, 153 COALESCE(act.dur, fallback.dur) AS dur, 154 do_frame.id AS do_frame_id, 155 draw_frame.id AS draw_frame_id, 156 draw_frame.render_thread_utid, 157 do_frame.ui_thread_utid, 158 "after_28" AS sdk, 159 act.id AS actual_frame_timeline_id, 160 exp.id AS expected_frame_timeline_id 161FROM android_frames_choreographer_do_frame do_frame 162JOIN android_frames_draw_frame draw_frame USING (frame_id, upid) 163JOIN fallback USING (frame_id) 164LEFT JOIN _distinct_from_actual_timeline_slice act USING (frame_id) 165LEFT JOIN _distinct_from_expected_timeline_slice exp USING (frame_id) 166ORDER BY frame_id 167), 168all_frames AS ( 169 SELECT * FROM frames_sdk_after_28 170 UNION 171 SELECT 172 *, 173 NULL AS actual_frame_timeline_id, 174 NULL AS expected_frame_timeline_id 175 FROM _frames_maxsdk_28 176) 177SELECT 178 frame_id, 179 ts, 180 dur, 181 do_frame_id, 182 draw_frame_id, 183 actual_frame_timeline_id, 184 expected_frame_timeline_id, 185 render_thread_utid, 186 ui_thread_utid 187FROM all_frames 188WHERE sdk = IIF( 189 (SELECT COUNT(1) FROM actual_frame_timeline_slice) > 0, 190 "after_28", "maxsdk28"); 191 192-- Returns first frame after the provided timestamp. The returning table has at 193-- most one row. 194CREATE PERFETTO FUNCTION android_first_frame_after( 195 -- Timestamp. 196 ts INT) 197RETURNS TABLE ( 198 -- Frame id. 199 frame_id INT, 200 -- Start of the frame, the timestamp of the "Choreographer#doFrame" slice. 201 ts INT, 202 -- Duration of the frame. 203 dur INT, 204 -- `slice.id` of "Choreographer#doFrame" slice. 205 do_frame_id INT, 206 -- `slice.id` of "DrawFrame" slice. 207 draw_frame_id INT, 208 -- `slice.id` from `actual_frame_timeline_slice` 209 actual_frame_timeline_id INT, 210 -- `slice.id` from `expected_frame_timeline_slice` 211 expected_frame_timeline_id INT, 212 -- `utid` of the render thread. 213 render_thread_utid INT, 214 -- `utid` of the UI thread. 215 ui_thread_utid INT 216) AS 217SELECT * FROM android_frames 218WHERE ts > $ts 219ORDER BY ts 220LIMIT 1;