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