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 22INCLUDE PERFETTO MODULE android.slices; 23INCLUDE PERFETTO MODULE android.binder; 24INCLUDE PERFETTO MODULE android.critical_blocking_calls; 25 26-- Jank "J<*>" and latency "L<*>" cujs are put together in android_cujs table. 27-- They are computed separately as latency ones are slightly different, don't 28-- currently have the same way to be cancelled, and are not anchored to vsyncs. 29DROP TABLE IF EXISTS android_cujs; 30CREATE TABLE android_cujs AS 31WITH latency_cujs AS ( 32 SELECT 33 ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, 34 process.upid AS upid, 35 -- Latency CUJs don't have a well defined thread. Let's always consider 36 -- the app main thread for those. 37 process.upid AS utid, 38 process.name AS process_name, 39 process_metadata.metadata AS process_metadata, 40 -- Extracts "CUJ_NAME" from "L<CUJ_NAME>" 41 SUBSTR(slice.name, 3, LENGTH(slice.name) - 3) AS cuj_name, 42 ts, 43 dur, 44 ts + dur AS ts_end, 45 'completed' AS state 46 FROM slice 47 JOIN process_track 48 ON slice.track_id = process_track.id 49 JOIN process USING (upid) 50 JOIN process_metadata USING (upid) 51 WHERE 52 slice.name GLOB 'L<*>' 53 AND dur > 0 54), 55all_cujs AS ( 56 SELECT 57 cuj_id, 58 cuj.upid, 59 t.utid as ui_thread, 60 process_name, 61 process_metadata, 62 cuj_name, 63 tb.ts, 64 tb.dur, 65 tb.ts_end 66 FROM android_jank_cuj_main_thread_cuj_boundary tb 67 JOIN android_jank_cuj cuj USING (cuj_id) 68 JOIN android_jank_cuj_main_thread t USING (cuj_id) 69UNION 70 SELECT 71 cuj_id, 72 upid, 73 utid as ui_thread, 74 process_name, 75 process_metadata, 76 cuj_name, 77 ts, 78 dur, 79 ts_end 80 FROM latency_cujs 81) 82SELECT ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, * 83FROM all_cujs; 84 85-- We have: 86-- (1) a list of slices from the main thread of each process from the 87-- all_main_thread_relevant_slices table. 88-- (2) a list of android cuj with beginning, end, and process 89-- It's needed to: 90-- (1) assign a cuj to each slice. If there are multiple cujs going on during a 91-- slice, there needs to be 2 entries for that slice, one for each cuj id. 92-- (2) each slice needs to be trimmed to be fully inside the cuj associated 93-- (as we don't care about what's outside cujs) 94DROP TABLE IF EXISTS main_thread_slices_scoped_to_cujs; 95CREATE PERFETTO TABLE main_thread_slices_scoped_to_cujs AS 96SELECT 97 s.id, 98 s.id AS slice_id, 99 s.name, 100 max(s.ts, cuj.ts) AS ts, 101 min(s.ts + s.dur, cuj.ts_end) as ts_end, 102 min(s.ts + s.dur, cuj.ts_end) - max(s.ts, cuj.ts) AS dur, 103 cuj.cuj_id, 104 cuj.cuj_name, 105 s.process_name, 106 s.upid, 107 s.utid 108FROM _android_critical_blocking_calls s 109 JOIN android_cujs cuj 110 -- only when there is an overlap 111 ON s.ts + s.dur > cuj.ts AND s.ts < cuj.ts_end 112 -- and are from the same process 113 AND s.upid = cuj.upid 114 -- from the CUJ ui thread only 115 AND s.utid = cuj.ui_thread; 116 117 118DROP TABLE IF EXISTS android_blocking_calls_cuj_calls; 119CREATE TABLE android_blocking_calls_cuj_calls AS 120SELECT 121 name, 122 COUNT(*) AS occurrences, 123 MAX(dur) AS max_dur_ns, 124 MIN(dur) AS min_dur_ns, 125 SUM(dur) AS total_dur_ns, 126 upid, 127 cuj_id, 128 cuj_name, 129 process_name 130FROM 131 main_thread_slices_scoped_to_cujs 132GROUP BY name, upid, cuj_id, cuj_name, process_name 133ORDER BY cuj_id; 134 135 136DROP VIEW IF EXISTS android_blocking_calls_cuj_metric_output; 137CREATE PERFETTO VIEW android_blocking_calls_cuj_metric_output AS 138SELECT AndroidBlockingCallsCujMetric('cuj', ( 139 SELECT RepeatedField( 140 AndroidBlockingCallsCujMetric_Cuj( 141 'id', cuj_id, 142 'name', cuj_name, 143 'process', process_metadata, 144 'ts', cuj.ts, 145 'dur', cuj.dur, 146 'blocking_calls', ( 147 SELECT RepeatedField( 148 AndroidBlockingCall( 149 'name', b.name, 150 'cnt', b.occurrences, 151 'total_dur_ms', CAST(total_dur_ns / 1e6 AS INT), 152 'max_dur_ms', CAST(max_dur_ns / 1e6 AS INT), 153 'min_dur_ms', CAST(min_dur_ns / 1e6 AS INT), 154 'total_dur_ns', b.total_dur_ns, 155 'max_dur_ns', b.max_dur_ns, 156 'min_dur_ns', b.min_dur_ns 157 ) 158 ) 159 FROM android_blocking_calls_cuj_calls b 160 WHERE b.cuj_id = cuj.cuj_id and b.upid = cuj.upid 161 ORDER BY total_dur_ns DESC 162 ) 163 ) 164 ) 165 FROM android_cujs cuj 166 ORDER BY cuj.cuj_id ASC 167)); 168