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