• 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
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;