• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2022 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 android.frames.jank_type;
17
18DROP TABLE IF EXISTS vsync_missed_callback;
19CREATE PERFETTO TABLE vsync_missed_callback AS
20SELECT CAST(STR_SPLIT(name, 'Callback#', 1) AS INTEGER) AS vsync,
21       MAX(name GLOB '*SF*') as sf_callback_missed,
22       MAX(name GLOB '*HWUI*') as hwui_callback_missed
23FROM slice
24WHERE name GLOB '*FT#Missed*Callback*'
25GROUP BY vsync;
26
27DROP TABLE IF EXISTS android_jank_cuj_frame_timeline;
28CREATE PERFETTO TABLE android_jank_cuj_frame_timeline AS
29WITH actual_timeline_with_vsync AS (
30  SELECT
31    *,
32    CAST(name AS INTEGER) AS vsync
33  FROM actual_frame_timeline_slice
34  WHERE dur > 0
35)
36SELECT
37  cuj_id,
38  vsync,
39  -- We use MAX to check if at least one of the layers jank_type matches the pattern
40  MAX(android_is_app_jank_type(jank_type)) AS app_missed,
41  -- We use MAX to check if at least one of the layers jank_type matches the pattern
42  MAX(android_is_sf_jank_type(jank_type)) AS sf_missed,
43  IFNULL(MAX(sf_callback_missed), 0) AS sf_callback_missed,
44  IFNULL(MAX(hwui_callback_missed), 0) AS hwui_callback_missed,
45  -- We use MIN to check if ALL layers finished on time
46  MIN(on_time_finish) AS on_time_finish,
47  MAX(timeline.ts + timeline.dur) AS ts_end_actual,
48  MAX(timeline.dur) AS dur,
49  -- At the moment of writing we expect to see at most one expected_frame_timeline_slice
50  -- for a given vsync but using MAX here in case this changes in the future.
51  -- In case expected timeline is missing, as a fallback we use the typical frame deadline
52  -- for 60Hz.
53  COALESCE(MAX(expected.dur), 16600000) AS dur_expected,
54  COUNT(DISTINCT timeline.layer_name) as number_of_layers_for_frame,
55  -- we use MAX to get at least one of the frame's layer names
56  MAX(timeline.layer_name) as frame_layer_name
57FROM android_jank_cuj_vsync_boundary boundary
58JOIN actual_timeline_with_vsync timeline
59  ON vsync >= vsync_min
60     AND vsync <= vsync_max
61LEFT JOIN expected_frame_timeline_slice expected
62  ON expected.upid = timeline.upid AND expected.name = timeline.name
63LEFT JOIN vsync_missed_callback missed_callback USING(vsync)
64WHERE
65  boundary.layer_id IS NULL
66  OR (
67    timeline.layer_name GLOB '*#*'
68    AND boundary.layer_id
69      = CAST(STR_SPLIT(timeline.layer_name, '#', 1) AS INTEGER))
70GROUP BY cuj_id, vsync;
71
72DROP TABLE IF EXISTS android_jank_cuj_layer_name;
73CREATE PERFETTO TABLE android_jank_cuj_layer_name AS
74SELECT
75    cuj_id,
76    MAX(frame_layer_name) as layer_name
77FROM android_jank_cuj_frame_timeline timeline
78GROUP BY cuj_id
79-- Return only cujs where the max number of layers for all frames in the whole cuj equals 1,
80-- this is to infer the layer name if the cuj marker for layer id is not present
81HAVING MAX(number_of_layers_for_frame) = 1;
82
83-- Matches slices and boundaries to compute estimated frame boundaries across
84-- all threads. Joins with the actual timeline to figure out which frames missed
85-- the deadline and whether the app process or SF are at fault.
86DROP TABLE IF EXISTS android_jank_cuj_frame;
87CREATE PERFETTO TABLE android_jank_cuj_frame AS
88WITH frame_base AS (
89  SELECT
90    cuj_id,
91    ROW_NUMBER() OVER (PARTITION BY cuj_id ORDER BY do_frame.vsync ASC) AS frame_number,
92    vsync,
93    boundary.ts,
94    boundary.ts_expected,
95    boundary.ts_do_frame_start,
96    COUNT(fence_idx) AS gpu_fence_count,
97    COUNT(fence_idx) > 0 AS drew_anything
98  FROM android_jank_cuj_do_frame_slice do_frame
99  JOIN android_jank_cuj_main_thread_frame_boundary boundary USING (cuj_id, vsync)
100  JOIN android_jank_cuj_draw_frame_slice draw_frame USING (cuj_id, vsync)
101  LEFT JOIN android_jank_cuj_gpu_completion_fence fence USING (cuj_id, vsync)
102  WHERE draw_frame.id = fence.draw_frame_slice_id
103  GROUP BY cuj_id, vsync, boundary.ts, boundary.ts_do_frame_start
104)
105SELECT
106  frame_base.*,
107  app_missed,
108  sf_missed,
109  sf_callback_missed,
110  hwui_callback_missed,
111  on_time_finish,
112  ts_end_actual - ts AS dur,
113  ts_end_actual - ts_do_frame_start AS dur_unadjusted,
114  dur_expected,
115  ts_end_actual AS ts_end
116FROM frame_base
117JOIN android_jank_cuj_frame_timeline USING (cuj_id, vsync);
118
119-- Similar to `android_jank_cuj_frame` computes overall SF frame boundaries.
120-- The computation is somewhat simpler as most of SF work happens within the duration of
121-- the commit/composite slices on the main thread.
122DROP TABLE IF EXISTS android_jank_cuj_sf_frame;
123CREATE PERFETTO TABLE android_jank_cuj_sf_frame AS
124WITH android_jank_cuj_timeline_sf_frame AS (
125    SELECT DISTINCT
126      cuj_id,
127      CAST(timeline.name AS INTEGER) AS vsync,
128      timeline.display_frame_token
129    FROM android_jank_cuj_vsync_boundary boundary
130    JOIN actual_frame_timeline_slice timeline
131      ON
132        boundary.upid = timeline.upid
133        AND CAST(timeline.name AS INTEGER) >= vsync_min
134        AND CAST(timeline.name AS INTEGER) <= vsync_max
135    WHERE
136        boundary.layer_id IS NULL
137      OR (
138        timeline.layer_name GLOB '*#*'
139        AND boundary.layer_id = CAST(STR_SPLIT(timeline.layer_name, '#', 1) AS INTEGER))
140),
141android_jank_cuj_sf_frame_base AS (
142    SELECT DISTINCT
143      boundary.cuj_id,
144      boundary.vsync,
145      boundary.ts,
146      boundary.ts_main_thread_start,
147      boundary.ts_end,
148      boundary.dur,
149      actual_timeline.jank_tag = 'Self Jank' AS sf_missed,
150      NULL AS app_missed, -- for simplicity align schema with android_jank_cuj_frame
151      jank_tag,
152      jank_type,
153      prediction_type,
154      present_type,
155      gpu_composition,
156      -- In case expected timeline is missing, as a fallback we use the typical frame deadline
157      -- for 60Hz.
158      -- See similar expression in android_jank_cuj_frame_timeline.
159      COALESCE(expected_timeline.dur, 16600000) AS dur_expected
160    FROM android_jank_cuj_sf_main_thread_frame_boundary boundary
161    JOIN android_jank_cuj_sf_process sf_process
162    JOIN actual_frame_timeline_slice actual_timeline
163      ON actual_timeline.upid = sf_process.upid
164        AND boundary.vsync = CAST(actual_timeline.name AS INTEGER)
165    JOIN android_jank_cuj_timeline_sf_frame ft
166      ON CAST(actual_timeline.name AS INTEGER) = ft.display_frame_token
167        AND boundary.cuj_id = ft.cuj_id
168    LEFT JOIN expected_frame_timeline_slice expected_timeline
169      ON expected_timeline.upid = actual_timeline.upid
170        AND expected_timeline.name = actual_timeline.name
171)
172SELECT
173 *,
174 ROW_NUMBER() OVER (PARTITION BY cuj_id ORDER BY vsync ASC) AS frame_number
175FROM android_jank_cuj_sf_frame_base;
176