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