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