• 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
16CREATE OR REPLACE PERFETTO FUNCTION vsync_from_name(slice_name STRING)
17RETURNS STRING AS
18SELECT CAST(STR_SPLIT($slice_name, " ", 1) AS INTEGER);
19
20CREATE OR REPLACE PERFETTO FUNCTION gpu_completion_fence_id_from_name(slice_name STRING)
21RETURNS STRING AS
22SELECT
23  CASE
24    WHEN
25      $slice_name GLOB "GPU completion fence *"
26    THEN
27      CAST(STR_SPLIT($slice_name, " ", 3) AS INTEGER)
28    WHEN
29      $slice_name GLOB "Trace GPU completion fence *"
30    THEN
31      CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
32    WHEN
33      $slice_name GLOB "waiting for GPU completion *"
34    THEN
35      CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
36    WHEN
37      $slice_name GLOB "Trace HWC release fence *"
38    THEN
39      CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
40    WHEN
41      $slice_name GLOB "waiting for HWC release *"
42    THEN
43      CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
44    ELSE NULL
45  END;
46
47-- Find Choreographer#doFrame slices that are between the CUJ markers.
48-- We extract vsync IDs from doFrame slice names and use these as the source
49-- of truth that allow us to get correct slices on the other threads.
50DROP TABLE IF EXISTS android_jank_cuj_do_frame_slice;
51CREATE PERFETTO TABLE android_jank_cuj_do_frame_slice AS
52SELECT
53  cuj.cuj_id,
54  main_thread.upid,
55  main_thread.utid,
56  slice.*,
57  slice.ts + slice.dur AS ts_end,
58  vsync_from_name(slice.name) AS vsync
59FROM android_jank_cuj cuj
60JOIN slice
61  ON slice.ts + slice.dur >= cuj.ts AND slice.ts <= cuj.ts_end
62JOIN android_jank_cuj_main_thread main_thread
63  ON cuj.cuj_id = main_thread.cuj_id
64    AND main_thread.track_id = slice.track_id
65WHERE
66  slice.name GLOB 'Choreographer#doFrame*'
67-- Ignore child slice e.g. "Choreographer#doFrame - resynced to 1234 in 20.0ms"
68  AND slice.name not GLOB '*resynced*'
69  AND slice.dur > 0
70  AND vsync > 0
71  AND (vsync >= begin_vsync OR begin_vsync is NULL)
72  AND (vsync <= end_vsync OR end_vsync is NULL)
73  -- In some malformed traces we see nested doFrame slices.
74  -- If that is the case, we ignore all parent doFrames and only keep the one
75  -- the lowest in the hierarchy.
76  AND NOT EXISTS (
77    SELECT 1 FROM descendant_slice(slice.id) child
78    WHERE child.name GLOB 'Choreographer#doFrame*'
79    AND child.name NOT GLOB '*resynced*'
80  );
81
82
83-- Store render thread DrawFrames by matching in the vsync IDs extracted from
84-- doFrame slices. In case of multiple layers being drawn, there might be
85-- multiple DrawFrames for a single vsync.
86DROP TABLE IF EXISTS android_jank_cuj_draw_frame_slice;
87CREATE PERFETTO TABLE android_jank_cuj_draw_frame_slice AS
88SELECT
89  cuj_id,
90  render_thread.upid,
91  render_thread.utid,
92  slice.*,
93  slice.ts + slice.dur AS ts_end,
94  vsync_from_name(slice.name) AS vsync
95FROM android_jank_cuj_do_frame_slice do_frame
96JOIN android_jank_cuj_render_thread render_thread USING (cuj_id)
97JOIN slice
98  ON slice.track_id = render_thread.track_id
99WHERE slice.name GLOB 'DrawFrame*'
100  AND vsync_from_name(slice.name) = do_frame.vsync
101  AND slice.dur > 0;
102
103-- Find descendants of DrawFrames which contain the GPU completion fence ID that
104-- is used for signaling that the GPU finished drawing.
105DROP TABLE IF EXISTS android_jank_cuj_gpu_completion_fence;
106CREATE PERFETTO TABLE android_jank_cuj_gpu_completion_fence AS
107SELECT
108  cuj_id,
109  vsync,
110  draw_frame.id AS draw_frame_slice_id,
111  gpu_completion_fence_id_from_name(fence.name) AS fence_idx
112FROM android_jank_cuj_draw_frame_slice draw_frame
113JOIN descendant_slice(draw_frame.id) fence
114  ON fence.name GLOB '*GPU completion fence*';
115
116-- Similarly find descendants of DrawFrames which have the HWC release fence ID
117DROP TABLE IF EXISTS android_jank_cuj_hwc_release_fence;
118CREATE PERFETTO TABLE android_jank_cuj_hwc_release_fence AS
119SELECT
120  cuj_id,
121  vsync,
122  draw_frame.id AS draw_frame_slice_id,
123  gpu_completion_fence_id_from_name(fence.name) AS fence_idx
124FROM android_jank_cuj_draw_frame_slice draw_frame
125JOIN descendant_slice(draw_frame.id) fence
126  ON fence.name GLOB '*HWC release fence *';
127
128-- Find HWC release slices which indicate when the HWC released the buffer.
129DROP TABLE IF EXISTS android_jank_cuj_hwc_release_slice;
130CREATE PERFETTO TABLE android_jank_cuj_hwc_release_slice AS
131SELECT
132  fence.cuj_id,
133  vsync,
134  slice.*,
135  slice.ts + slice.dur AS ts_end,
136  fence.fence_idx,
137  draw_frame_slice_id
138FROM android_jank_cuj_hwc_release_thread hwc_release_thread
139JOIN slice USING (track_id)
140JOIN android_jank_cuj_hwc_release_fence fence
141  ON fence.cuj_id = hwc_release_thread.cuj_id
142    AND fence.fence_idx = gpu_completion_fence_id_from_name(slice.name)
143WHERE
144  slice.name GLOB 'waiting for HWC release *'
145  AND slice.dur > 0;
146
147-- Find GPU completion slices which indicate when the GPU finished drawing.
148DROP TABLE IF EXISTS android_jank_cuj_gpu_completion_slice;
149CREATE PERFETTO TABLE android_jank_cuj_gpu_completion_slice AS
150SELECT
151  fence.cuj_id,
152  vsync,
153  slice.*,
154  slice.ts + slice.dur AS ts_end,
155  hwc_release.ts_end AS hwc_release_ts_end,
156  fence.fence_idx
157FROM android_jank_cuj_gpu_completion_thread gpu_completion_thread
158JOIN slice USING (track_id)
159JOIN android_jank_cuj_gpu_completion_fence fence
160  ON fence.cuj_id = gpu_completion_thread.cuj_id
161  AND fence.fence_idx = gpu_completion_fence_id_from_name(slice.name)
162LEFT JOIN android_jank_cuj_hwc_release_slice hwc_release
163  USING (cuj_id, vsync, draw_frame_slice_id)
164WHERE
165  slice.name GLOB 'waiting for GPU completion *'
166  AND slice.dur > 0;
167
168-- Match the frame timeline on the app side with the frame timeline on the SF side.
169-- This way we get the vsyncs IDs of SF frames within the CUJ.
170-- Note that there might be multiple SF vsync IDs that match a single App vsync ID, e.g.
171-- if one App layer produced a frame later and it was picked up by the next SF frame.
172DROP TABLE IF EXISTS android_jank_cuj_app_to_sf_match;
173CREATE PERFETTO TABLE android_jank_cuj_app_to_sf_match AS
174SELECT
175  cuj_id,
176  do_frame.upid AS app_upid,
177  do_frame.vsync AS app_vsync,
178  sf_process.upid AS sf_upid,
179  CAST(sf_timeline.name AS INTEGER) AS sf_vsync
180FROM android_jank_cuj_do_frame_slice do_frame
181JOIN actual_frame_timeline_slice app_timeline
182  ON do_frame.upid = app_timeline.upid
183    AND do_frame.vsync = CAST(app_timeline.name AS INTEGER)
184JOIN directly_connected_flow(app_timeline.id) flow
185  ON flow.slice_out = app_timeline.id
186JOIN actual_frame_timeline_slice sf_timeline
187  ON flow.slice_in = sf_timeline.id
188JOIN android_jank_cuj_sf_process sf_process
189  ON sf_timeline.upid = sf_process.upid
190-- In cases where there are multiple layers drawn we would have separate frame timeline
191-- slice for each of the layers. GROUP BY to deduplicate these rows.
192GROUP BY cuj_id, app_upid, app_vsync, sf_upid, sf_vsync;
193
194CREATE OR REPLACE PERFETTO FUNCTION find_android_jank_cuj_sf_main_thread_slice(
195  slice_name_glob STRING)
196RETURNS TABLE(
197  cuj_id INT, utid INT, vsync INT, id INT,
198  name STRING, ts LONG, dur LONG, ts_end LONG)
199AS
200WITH sf_vsync AS (
201  SELECT DISTINCT cuj_id, sf_vsync AS vsync
202  FROM android_jank_cuj_app_to_sf_match)
203SELECT
204  cuj_id,
205  utid,
206  sf_vsync.vsync,
207  slice.id,
208  slice.name,
209  slice.ts,
210  slice.dur,
211  slice.ts + slice.dur AS ts_end
212FROM slice
213JOIN android_jank_cuj_sf_main_thread main_thread USING (track_id)
214JOIN sf_vsync
215  ON vsync_from_name(slice.name) = sf_vsync.vsync
216WHERE slice.name GLOB $slice_name_glob AND slice.dur > 0
217ORDER BY cuj_id, vsync;
218
219DROP TABLE IF EXISTS android_jank_cuj_sf_commit_slice;
220CREATE PERFETTO TABLE android_jank_cuj_sf_commit_slice AS
221SELECT * FROM FIND_ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE('commit *');
222
223DROP TABLE IF EXISTS android_jank_cuj_sf_composite_slice;
224CREATE PERFETTO TABLE android_jank_cuj_sf_composite_slice AS
225SELECT * FROM FIND_ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE('composite *');
226
227-- Older builds do not have the commit/composite but onMessageInvalidate instead
228DROP TABLE IF EXISTS android_jank_cuj_sf_on_message_invalidate_slice;
229CREATE PERFETTO TABLE android_jank_cuj_sf_on_message_invalidate_slice AS
230SELECT * FROM FIND_ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE('onMessageInvalidate *');
231
232DROP VIEW IF EXISTS android_jank_cuj_sf_root_slice;
233CREATE PERFETTO VIEW android_jank_cuj_sf_root_slice AS
234SELECT * FROM android_jank_cuj_sf_commit_slice
235UNION ALL
236SELECT * FROM android_jank_cuj_sf_composite_slice
237UNION ALL
238SELECT * FROM android_jank_cuj_sf_on_message_invalidate_slice;
239
240-- Find descendants of SF main thread slices which contain the GPU completion fence ID that
241-- is used for signaling that the GPU finished drawing.
242DROP TABLE IF EXISTS android_jank_cuj_sf_gpu_completion_fence;
243CREATE PERFETTO TABLE android_jank_cuj_sf_gpu_completion_fence AS
244SELECT
245  cuj_id,
246  vsync,
247  sf_root_slice.id AS sf_root_slice_id,
248  gpu_completion_fence_id_from_name(fence.name) AS fence_idx
249FROM android_jank_cuj_sf_root_slice sf_root_slice
250JOIN descendant_slice(sf_root_slice.id) fence
251  ON fence.name GLOB '*GPU completion fence*';
252
253-- Find GPU completion slices which indicate when the GPU finished drawing.
254DROP TABLE IF EXISTS android_jank_cuj_sf_gpu_completion_slice;
255CREATE PERFETTO TABLE android_jank_cuj_sf_gpu_completion_slice AS
256SELECT
257  fence.cuj_id,
258  vsync,
259  slice.*,
260  slice.ts + slice.dur AS ts_end,
261  fence.fence_idx
262FROM android_jank_cuj_sf_gpu_completion_fence fence
263JOIN android_jank_cuj_sf_gpu_completion_thread gpu_completion_thread
264JOIN slice
265  ON slice.track_id = gpu_completion_thread.track_id
266    AND fence.fence_idx = gpu_completion_fence_id_from_name(slice.name)
267WHERE
268  slice.name GLOB 'waiting for GPU completion *'
269  AND slice.dur > 0;
270
271
272-- Find REThreaded::drawLayers on RenderEngine thread.
273-- These will be only relevant if SF is doing client composition so we check if
274-- the drawLayers slice is completely within the bounds of composeSurfaces on SF
275-- main thread.
276DROP TABLE IF EXISTS android_jank_cuj_sf_draw_layers_slice;
277CREATE PERFETTO TABLE android_jank_cuj_sf_draw_layers_slice AS
278WITH compose_surfaces AS (
279  SELECT
280    cuj_id,
281    vsync,
282    sf_root_slice.id AS sf_root_slice_id,
283    compose_surfaces.ts,
284    compose_surfaces.ts + compose_surfaces.dur AS ts_end
285  FROM android_jank_cuj_sf_root_slice sf_root_slice
286  JOIN descendant_slice(sf_root_slice.id) compose_surfaces
287    ON compose_surfaces.name = 'composeSurfaces'
288)
289SELECT
290  cuj_id,
291  re_thread.utid,
292  vsync,
293  draw_layers.*,
294  draw_layers.ts + draw_layers.dur AS ts_end,
295  -- Store composeSurfaces ts as this will simplify calculating frame boundaries
296  compose_surfaces.ts AS ts_compose_surfaces
297FROM compose_surfaces
298JOIN android_jank_cuj_sf_render_engine_thread re_thread
299JOIN slice draw_layers
300  ON draw_layers.track_id = re_thread.track_id
301    AND draw_layers.ts >= compose_surfaces.ts
302    AND draw_layers.ts + draw_layers.dur <= compose_surfaces.ts_end
303WHERE
304  draw_layers.name = 'REThreaded::drawLayers'
305  AND draw_layers.dur > 0;
306