1-- 2-- Copyright 2023 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 16-- Create the base table (`android_jank_cuj`) containing all completed CUJs 17-- found in the trace. 18-- This script will use the `android_jank_cuj_main_thread_cuj_boundary`, 19-- containing bounds of jank CUJs. 20SELECT RUN_METRIC('android/android_jank_cuj.sql'); 21 22SELECT IMPORT('android.slices'); 23SELECT IMPORT('android.binder'); 24 25-- Jank "J<*>" and latency "L<*>" cujs are put together in android_cujs table. 26-- They are computed separately as latency ones are slightly different, don't 27-- currently have the same way to be cancelled, and are not anchored to vsyncs. 28DROP TABLE IF EXISTS android_cujs; 29CREATE TABLE android_cujs AS 30WITH latency_cujs AS ( 31 SELECT 32 ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, 33 process.upid AS upid, 34 process.name AS process_name, 35 process_metadata.metadata AS process_metadata, 36 -- Extracts "CUJ_NAME" from "L<CUJ_NAME>" 37 SUBSTR(slice.name, 3, LENGTH(slice.name) - 3) AS cuj_name, 38 ts, 39 dur, 40 ts + dur AS ts_end, 41 'completed' AS state 42 FROM slice 43 JOIN process_track 44 ON slice.track_id = process_track.id 45 JOIN process USING (upid) 46 JOIN process_metadata USING (upid) 47 WHERE 48 slice.name GLOB 'L<*>' 49 AND dur > 0 50), 51all_cujs AS ( 52 SELECT 53 cuj_id, 54 upid, 55 process_name, 56 process_metadata, 57 cuj_name, 58 tb.ts, 59 tb.dur, 60 tb.ts_end 61 FROM android_jank_cuj_main_thread_cuj_boundary tb 62 JOIN android_jank_cuj using (cuj_id) 63UNION 64 SELECT 65 cuj_id, 66 upid, 67 process_name, 68 process_metadata, 69 cuj_name, 70 ts, 71 dur, 72 ts_end 73 FROM latency_cujs 74) 75SELECT ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, * 76FROM all_cujs; 77 78 79DROP TABLE IF EXISTS relevant_binder_calls_with_names; 80CREATE TABLE relevant_binder_calls_with_names AS 81SELECT DISTINCT 82 tx.aidl_name AS name, 83 tx.client_ts AS ts, 84 s.track_id, 85 tx.client_dur AS dur, 86 s.id, 87 tx.client_process as process_name, 88 tx.client_utid as utid, 89 tx.client_upid as upid 90FROM android_sync_binder_metrics_by_txn AS tx 91 JOIN slice AS s ON s.id = tx.binder_txn_id 92 -- Keeps only slices in cuj processes. 93 JOIN android_cujs ON tx.client_upid = android_cujs.upid 94WHERE is_main_thread AND aidl_name IS NOT NULL; 95 96 97DROP TABLE IF EXISTS android_blocking_calls_cuj_calls; 98CREATE TABLE android_blocking_calls_cuj_calls AS 99WITH all_main_thread_relevant_slices AS ( 100 SELECT DISTINCT 101 ANDROID_STANDARDIZE_SLICE_NAME(s.name) AS name, 102 s.ts, 103 s.track_id, 104 s.dur, 105 s.id, 106 process.name AS process_name, 107 thread.utid, 108 process.upid 109 FROM slice s 110 JOIN thread_track ON s.track_id = thread_track.id 111 JOIN thread USING (utid) 112 JOIN process USING (upid) 113 JOIN android_cujs USING (upid) -- Keeps only slices in cuj processes. 114 WHERE 115 thread.is_main_thread AND ( 116 s.name = 'measure' 117 OR s.name = 'layout' 118 OR s.name = 'configChanged' 119 OR s.name = 'Contending for pthread mutex' 120 OR s.name GLOB 'monitor contention with*' 121 OR s.name GLOB 'SuspendThreadByThreadId*' 122 OR s.name GLOB 'LoadApkAssetsFd*' 123 OR s.name GLOB '*binder transaction*' 124 OR s.name GLOB 'inflate*' 125 OR s.name GLOB 'Lock contention on*' 126 OR s.name GLOB '*CancellableContinuationImpl*' 127 OR s.name GLOB 'relayoutWindow*' 128 OR s.name GLOB 'ImageDecoder#decode*' 129 ) 130 UNION ALL 131 SELECT 132 name, 133 ts, 134 track_id, 135 dur, 136 id, 137 process_name, 138 utid, 139 upid 140 FROM relevant_binder_calls_with_names 141), 142-- Now we have: 143-- (1) a list of slices from the main thread of each process 144-- (2) a list of android cuj with beginning, end, and process 145-- It's needed to: 146-- (1) assign a cuj to each slice. If there are multiple cujs going on during a 147-- slice, there needs to be 2 entries for that slice, one for each cuj id. 148-- (2) each slice needs to be trimmed to be fully inside the cuj associated 149-- (as we don't care about what's outside cujs) 150main_thread_slices_scoped_to_cujs AS ( 151SELECT 152 s.id, 153 s.id AS slice_id, 154 s.track_id, 155 s.name, 156 max(s.ts, cuj.ts) AS ts, 157 min(s.ts + s.dur, cuj.ts_end) as ts_end, 158 min(s.ts + s.dur, cuj.ts_end) - max(s.ts, cuj.ts) AS dur, 159 cuj.cuj_id, 160 cuj.cuj_name, 161 s.process_name, 162 s.upid, 163 s.utid 164FROM all_main_thread_relevant_slices s 165 JOIN android_cujs cuj 166 -- only when there is an overlap 167 ON s.ts + s.dur > cuj.ts AND s.ts < cuj.ts_end 168 -- and are from the same process 169 AND s.upid = cuj.upid 170) 171SELECT 172 name, 173 COUNT(*) AS occurrences, 174 CAST(MAX(dur) / 1e6 AS INT) AS max_dur_ms, 175 CAST(MIN(dur) / 1e6 AS INT) AS min_dur_ms, 176 CAST(SUM(dur) / 1e6 AS INT) AS total_dur_ms, 177 upid, 178 cuj_id, 179 cuj_name, 180 process_name 181FROM 182 main_thread_slices_scoped_to_cujs 183GROUP BY name, upid, cuj_id, cuj_name, process_name 184ORDER BY cuj_id; 185 186 187DROP VIEW IF EXISTS android_blocking_calls_cuj_metric_output; 188CREATE VIEW android_blocking_calls_cuj_metric_output AS 189SELECT AndroidBlockingCallsCujMetric('cuj', ( 190 SELECT RepeatedField( 191 AndroidBlockingCallsCujMetric_Cuj( 192 'id', cuj_id, 193 'name', cuj_name, 194 'process', process_metadata, 195 'ts', cuj.ts, 196 'dur', cuj.dur, 197 'blocking_calls', ( 198 SELECT RepeatedField( 199 AndroidBlockingCallsCujMetric_BlockingCall( 200 'name', b.name, 201 'cnt', b.occurrences, 202 'total_dur_ms', b.total_dur_ms, 203 'max_dur_ms', b.max_dur_ms, 204 'min_dur_ms', b.min_dur_ms 205 ) 206 ) 207 FROM android_blocking_calls_cuj_calls b 208 WHERE b.cuj_id = cuj.cuj_id and b.upid = cuj.upid 209 ORDER BY total_dur_ms DESC 210 ) 211 ) 212 ) 213 FROM android_cujs cuj 214 ORDER BY cuj.cuj_id ASC 215)); 216