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