• 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 time.conversion;
17
18INCLUDE PERFETTO MODULE android.frames.timeline;
19
20-- `actual_frame_timeline_slice` returns the same slice name for different layer IDs or tracks.
21-- This happens because there can be multiple slices associated with a single frame_id.
22-- We are interested in unique names(frame_id) and the respective counts.
23-- This is a legacy table which is moved to this file because the android_frames_overrun table depends on it.
24CREATE PERFETTO TABLE _frame_id_count_in_actual_timeline AS
25SELECT
26  cast_int!(name) AS frame_id,
27  min(id) AS id,
28  min(ts) AS ts,
29  max(dur) AS dur,
30  max(ts + dur) AS ts_end,
31  count() AS count
32FROM actual_frame_timeline_slice
33GROUP BY
34  1;
35
36-- `expected_frame_timeline_slice` returns the same slice name for different tracks.
37-- This happens because there can be multiple slices associated with a single frame_id.
38-- We are interested in unique names(frame_id) and the respective counts.
39-- This is a legacy table which is moved to this file because the android_frames_overrun table depends on it.
40CREATE PERFETTO TABLE _frame_id_count_in_expected_timeline AS
41SELECT
42  cast_int!(name) AS frame_id,
43  id,
44  count() AS count
45FROM expected_frame_timeline_slice
46GROUP BY
47  1;
48
49-- The amount by which each frame missed of hit its deadline. Negative if the
50-- deadline was not missed. Frames are considered janky if `overrun` is
51-- positive.
52-- Calculated as the difference between the end of the
53-- `expected_frame_timeline_slice` and `actual_frame_timeline_slice` for the
54-- frame.
55-- Availability: from S (API 31).
56-- For Googlers: more details in go/android-performance-metrics-glossary.
57CREATE PERFETTO TABLE android_frames_overrun (
58  -- Frame id.
59  frame_id LONG,
60  -- Difference between `expected` and `actual` frame ends. Negative if frame
61  -- didn't miss deadline.
62  overrun LONG
63) AS
64SELECT
65  frame_id,
66  (
67    act_slice.ts + act_slice.dur
68  ) - (
69    exp_slice.ts + exp_slice.dur
70  ) AS overrun
71FROM _frame_id_count_in_actual_timeline AS act
72JOIN _frame_id_count_in_expected_timeline AS exp
73  USING (frame_id)
74JOIN slice AS act_slice
75  ON (
76    act.id = act_slice.id
77  )
78JOIN slice AS exp_slice
79  ON (
80    exp.id = exp_slice.id
81  );
82
83-- How much time did the frame's Choreographer callbacks take.
84CREATE PERFETTO TABLE android_frames_ui_time (
85  -- Frame id
86  frame_id LONG,
87  -- UI time duration
88  ui_time LONG
89) AS
90SELECT
91  frame_id,
92  dur AS ui_time
93FROM android_frames_choreographer_do_frame AS f
94JOIN slice
95  USING (id);
96
97-- App Vsync delay for a frame. The time between the VSYNC-app signal and the
98-- start of Choreographer work.
99-- Calculated as time difference between the actual frame start (from
100-- `actual_frame_timeline_slice`) and start of the `Choreographer#doFrame`
101-- slice.
102-- For Googlers: more details in go/android-performance-metrics-glossary.
103CREATE PERFETTO TABLE android_app_vsync_delay_per_frame (
104  -- Frame id
105  frame_id LONG,
106  -- App VSYNC delay.
107  app_vsync_delay LONG
108) AS
109-- As there can be multiple `DrawFrame` slices, the `frames_surface_slices`
110-- table contains multiple rows for the same `frame_id` which only differ on
111-- `draw_frame_id`. As we don't care about `draw_frame_id` we can just collapse
112-- them.
113WITH
114  distinct_frames AS (
115    SELECT
116      frame_id,
117      do_frame_id,
118      actual_frame_timeline_id,
119      expected_frame_timeline_id
120    FROM android_frames
121    GROUP BY
122      1
123  )
124SELECT
125  frame_id,
126  act.ts - exp.ts AS app_vsync_delay
127FROM distinct_frames AS f
128JOIN slice AS exp
129  ON (
130    f.expected_frame_timeline_id = exp.id
131  )
132JOIN slice AS act
133  ON (
134    f.actual_frame_timeline_id = act.id
135  );
136
137-- How much time did the frame take across the UI Thread + RenderThread.
138-- Calculated as sum of `app VSYNC delay` `Choreographer#doFrame` slice
139-- duration and summed durations of all `DrawFrame` slices associated with this
140-- frame.
141-- Availability: from N (API 24).
142-- For Googlers: more details in go/android-performance-metrics-glossary.
143CREATE PERFETTO TABLE android_cpu_time_per_frame (
144  -- Frame id
145  frame_id LONG,
146  -- Difference between actual timeline of the frame and
147  -- `Choreographer#doFrame`. See `android_app_vsync_delay_per_frame` table for more details.
148  app_vsync_delay LONG,
149  -- Duration of `Choreographer#doFrame` slice.
150  do_frame_dur DURATION,
151  -- Duration of `DrawFrame` slice. Summed duration of all `DrawFrame`
152  -- slices, if more than one. See `android_frames_draw_frame` for more details.
153  draw_frame_dur DURATION,
154  -- CPU time across the UI Thread + RenderThread.
155  cpu_time LONG
156) AS
157WITH
158  all_draw_frames AS (
159    SELECT
160      frame_id,
161      sum(dur) AS draw_frame_dur
162    FROM android_frames_draw_frame
163    JOIN slice
164      USING (id)
165    GROUP BY
166      frame_id
167  ),
168  distinct_frames AS (
169    SELECT
170      frame_id,
171      do_frame_id,
172      actual_frame_timeline_id
173    FROM android_frames
174    GROUP BY
175      1
176  )
177SELECT
178  frame_id,
179  app_vsync_delay,
180  do_frame.dur AS do_frame_dur,
181  draw_frame_dur,
182  app_vsync_delay + do_frame.dur + draw_frame_dur AS cpu_time
183FROM android_app_vsync_delay_per_frame
184JOIN all_draw_frames
185  USING (frame_id)
186JOIN distinct_frames AS f
187  USING (frame_id)
188JOIN slice AS do_frame
189  ON (
190    f.do_frame_id = do_frame.id
191  );
192
193-- CPU time of frames which don't have `android_cpu_time_per_frame` available.
194-- Calculated as UI time of the frame + 5ms.
195-- For Googlers: more details in go/android-performance-metrics-glossary.
196CREATE PERFETTO TABLE _cpu_time_per_frame_fallback (
197  -- Frame id.
198  frame_id LONG,
199  -- Estimated cpu time.
200  estimated_cpu_time LONG
201) AS
202SELECT
203  frame_id,
204  ui_time + time_from_ms(5) AS estimated_cpu_time
205FROM android_frames_ui_time;
206
207CREATE PERFETTO TABLE _estimated_cpu_time_per_frame (
208  frame_id LONG,
209  cpu_time LONG
210) AS
211SELECT
212  frame_id,
213  iif(r.cpu_time IS NULL, f.estimated_cpu_time, r.cpu_time) AS cpu_time
214FROM _cpu_time_per_frame_fallback AS f
215LEFT JOIN android_cpu_time_per_frame AS r
216  USING (frame_id);
217
218-- Aggregated stats of the frame.
219--
220-- For Googlers: more details in go/android-performance-metrics-glossary.
221CREATE PERFETTO TABLE android_frame_stats (
222  -- Frame id.
223  frame_id LONG,
224  -- The amount by which each frame missed of hit its deadline. See
225  -- `android_frames_overrun` for details.
226  overrun LONG,
227  -- How much time did the frame take across the UI Thread + RenderThread.
228  cpu_time LONG,
229  -- How much time did the frame's Choreographer callbacks take.
230  ui_time LONG,
231  -- Was frame janky.
232  was_jank BOOL,
233  -- CPU time of the frame took over 20ms.
234  was_slow_frame BOOL,
235  -- CPU time of the frame took over 50ms.
236  was_big_jank BOOL,
237  -- CPU time of the frame took over 200ms.
238  was_huge_jank BOOL
239) AS
240SELECT
241  frame_id,
242  overrun,
243  cpu_time,
244  ui_time,
245  iif(overrun > 0, 1, NULL) AS was_jank,
246  iif(cpu_time > time_from_ms(20), 1, NULL) AS was_slow_frame,
247  iif(cpu_time > time_from_ms(50), 1, NULL) AS was_big_jank,
248  iif(cpu_time > time_from_ms(200), 1, NULL) AS was_huge_jank
249FROM android_frames_overrun
250JOIN android_frames_ui_time
251  USING (frame_id)
252JOIN _estimated_cpu_time_per_frame
253  USING (frame_id);
254