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 16INCLUDE PERFETTO MODULE android.frames.jank_type; 17 18DROP TABLE IF EXISTS vsync_missed_callback; 19CREATE PERFETTO TABLE vsync_missed_callback AS 20SELECT CAST(STR_SPLIT(name, 'Callback#', 1) AS INTEGER) AS vsync, 21 MAX(name GLOB '*SF*') as sf_callback_missed, 22 MAX(name GLOB '*HWUI*') as hwui_callback_missed 23FROM slice 24WHERE name GLOB '*FT#Missed*Callback*' 25GROUP BY vsync; 26 27DROP TABLE IF EXISTS android_jank_cuj_frame_timeline; 28CREATE PERFETTO TABLE android_jank_cuj_frame_timeline AS 29WITH actual_timeline_with_vsync AS ( 30 SELECT 31 *, 32 CAST(name AS INTEGER) AS vsync 33 FROM actual_frame_timeline_slice 34 WHERE dur > 0 35) 36SELECT 37 cuj_id, 38 vsync, 39 -- We use MAX to check if at least one of the layers jank_type matches the pattern 40 MAX(android_is_app_jank_type(jank_type)) AS app_missed, 41 -- We use MAX to check if at least one of the layers jank_type matches the pattern 42 MAX(android_is_sf_jank_type(jank_type)) AS sf_missed, 43 IFNULL(MAX(sf_callback_missed), 0) AS sf_callback_missed, 44 IFNULL(MAX(hwui_callback_missed), 0) AS hwui_callback_missed, 45 -- We use MIN to check if ALL layers finished on time 46 MIN(on_time_finish) AS on_time_finish, 47 MAX(timeline.ts + timeline.dur) AS ts_end_actual, 48 MAX(timeline.dur) AS dur, 49 -- At the moment of writing we expect to see at most one expected_frame_timeline_slice 50 -- for a given vsync but using MAX here in case this changes in the future. 51 -- In case expected timeline is missing, as a fallback we use the typical frame deadline 52 -- for 60Hz. 53 COALESCE(MAX(expected.dur), 16600000) AS dur_expected, 54 COUNT(DISTINCT timeline.layer_name) as number_of_layers_for_frame, 55 -- we use MAX to get at least one of the frame's layer names 56 MAX(timeline.layer_name) as frame_layer_name 57FROM android_jank_cuj_vsync_boundary boundary 58JOIN actual_timeline_with_vsync timeline 59 ON vsync >= vsync_min 60 AND vsync <= vsync_max 61LEFT JOIN expected_frame_timeline_slice expected 62 ON expected.upid = timeline.upid AND expected.name = timeline.name 63LEFT JOIN vsync_missed_callback missed_callback USING(vsync) 64WHERE 65 boundary.layer_id IS NULL 66 OR ( 67 timeline.layer_name GLOB '*#*' 68 AND boundary.layer_id 69 = CAST(STR_SPLIT(timeline.layer_name, '#', 1) AS INTEGER)) 70GROUP BY cuj_id, vsync; 71 72DROP TABLE IF EXISTS android_jank_cuj_layer_name; 73CREATE PERFETTO TABLE android_jank_cuj_layer_name AS 74SELECT 75 cuj_id, 76 MAX(frame_layer_name) as layer_name 77FROM android_jank_cuj_frame_timeline timeline 78GROUP BY cuj_id 79-- Return only cujs where the max number of layers for all frames in the whole cuj equals 1, 80-- this is to infer the layer name if the cuj marker for layer id is not present 81HAVING MAX(number_of_layers_for_frame) = 1; 82 83-- Matches slices and boundaries to compute estimated frame boundaries across 84-- all threads. Joins with the actual timeline to figure out which frames missed 85-- the deadline and whether the app process or SF are at fault. 86DROP TABLE IF EXISTS android_jank_cuj_frame; 87CREATE PERFETTO TABLE android_jank_cuj_frame AS 88WITH frame_base AS ( 89 SELECT 90 cuj_id, 91 ROW_NUMBER() OVER (PARTITION BY cuj_id ORDER BY do_frame.vsync ASC) AS frame_number, 92 vsync, 93 boundary.ts, 94 boundary.ts_expected, 95 boundary.ts_do_frame_start, 96 COUNT(fence_idx) AS gpu_fence_count, 97 COUNT(fence_idx) > 0 AS drew_anything 98 FROM android_jank_cuj_do_frame_slice do_frame 99 JOIN android_jank_cuj_main_thread_frame_boundary boundary USING (cuj_id, vsync) 100 JOIN android_jank_cuj_draw_frame_slice draw_frame USING (cuj_id, vsync) 101 LEFT JOIN android_jank_cuj_gpu_completion_fence fence USING (cuj_id, vsync) 102 WHERE draw_frame.id = fence.draw_frame_slice_id 103 GROUP BY cuj_id, vsync, boundary.ts, boundary.ts_do_frame_start 104) 105SELECT 106 frame_base.*, 107 app_missed, 108 sf_missed, 109 sf_callback_missed, 110 hwui_callback_missed, 111 on_time_finish, 112 ts_end_actual - ts AS dur, 113 ts_end_actual - ts_do_frame_start AS dur_unadjusted, 114 dur_expected, 115 ts_end_actual AS ts_end 116FROM frame_base 117JOIN android_jank_cuj_frame_timeline USING (cuj_id, vsync); 118 119-- Similar to `android_jank_cuj_frame` computes overall SF frame boundaries. 120-- The computation is somewhat simpler as most of SF work happens within the duration of 121-- the commit/composite slices on the main thread. 122DROP TABLE IF EXISTS android_jank_cuj_sf_frame; 123CREATE PERFETTO TABLE android_jank_cuj_sf_frame AS 124WITH android_jank_cuj_timeline_sf_frame AS ( 125 SELECT DISTINCT 126 cuj_id, 127 CAST(timeline.name AS INTEGER) AS vsync, 128 timeline.display_frame_token 129 FROM android_jank_cuj_vsync_boundary boundary 130 JOIN actual_frame_timeline_slice timeline 131 ON 132 boundary.upid = timeline.upid 133 AND CAST(timeline.name AS INTEGER) >= vsync_min 134 AND CAST(timeline.name AS INTEGER) <= vsync_max 135 WHERE 136 boundary.layer_id IS NULL 137 OR ( 138 timeline.layer_name GLOB '*#*' 139 AND boundary.layer_id = CAST(STR_SPLIT(timeline.layer_name, '#', 1) AS INTEGER)) 140), 141android_jank_cuj_sf_frame_base AS ( 142 SELECT DISTINCT 143 boundary.cuj_id, 144 boundary.vsync, 145 boundary.ts, 146 boundary.ts_main_thread_start, 147 boundary.ts_end, 148 boundary.dur, 149 actual_timeline.jank_tag = 'Self Jank' AS sf_missed, 150 NULL AS app_missed, -- for simplicity align schema with android_jank_cuj_frame 151 jank_tag, 152 jank_type, 153 prediction_type, 154 present_type, 155 gpu_composition, 156 -- In case expected timeline is missing, as a fallback we use the typical frame deadline 157 -- for 60Hz. 158 -- See similar expression in android_jank_cuj_frame_timeline. 159 COALESCE(expected_timeline.dur, 16600000) AS dur_expected 160 FROM android_jank_cuj_sf_main_thread_frame_boundary boundary 161 JOIN android_jank_cuj_sf_process sf_process 162 JOIN actual_frame_timeline_slice actual_timeline 163 ON actual_timeline.upid = sf_process.upid 164 AND boundary.vsync = CAST(actual_timeline.name AS INTEGER) 165 JOIN android_jank_cuj_timeline_sf_frame ft 166 ON CAST(actual_timeline.name AS INTEGER) = ft.display_frame_token 167 AND boundary.cuj_id = ft.cuj_id 168 LEFT JOIN expected_frame_timeline_slice expected_timeline 169 ON expected_timeline.upid = actual_timeline.upid 170 AND expected_timeline.name = actual_timeline.name 171) 172SELECT 173 *, 174 ROW_NUMBER() OVER (PARTITION BY cuj_id ORDER BY vsync ASC) AS frame_number 175FROM android_jank_cuj_sf_frame_base; 176