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-- 16-- WARNING: This metric should not be used as a source of truth. It is under 17-- active development and the values & meaning might change without 18-- notice. 19 20-- Given a slice id of an event, get timestamp of the most recent flow 21-- event on the Chrome IO thread that preceded this slice. 22-- This helps us identify the last flow event on the IO thread before 23-- letting the browser main thread be aware of input. 24-- We need this for flings (generated by the GPU process) and blocked 25-- touch moves that are forwarded from the renderer. 26-- Returning the slice id for the flow_out on the chrome IO thread. 27CREATE OR REPLACE PERFETTO FUNCTION {{function_prefix}}PRECEDING_IO_THREAD_EVENT_FLOW_ID(id LONG) 28RETURNS LONG AS 29SELECT MAX(flow.slice_out) AS id 30FROM PRECEDING_FLOW(($id)) flow; 31 32-- Returns a Chrome task which contains the given slice. 33CREATE OR REPLACE PERFETTO FUNCTION {{function_prefix}}GET_ENCLOSING_CHROME_TASK_NAME( 34 slice_id LONG 35) 36RETURNS STRING AS 37SELECT 38 task.name 39FROM ancestor_slice($slice_id) 40JOIN chrome_tasks task USING (id) 41LIMIT 1; 42 43CREATE OR REPLACE PERFETTO FUNCTION {{function_prefix}}GET_SCROLL_TYPE( 44 blocked_gesture BOOL, 45 task_name STRING 46) 47RETURNS STRING AS 48SELECT 49 CASE WHEN ($blocked_gesture) 50 THEN (SELECT 51 CASE WHEN ($task_name) glob "viz.mojom.BeginFrameObserver *" 52 THEN "fling" 53 WHEN ($task_name) glob "blink.mojom.WidgetInputHandler *" 54 THEN "blocking_touch_move" 55 ELSE "unknown" END) 56 ELSE "regular" END AS delay_type; 57 58-- Get all InputLatency::GestureScrollUpdate events, to use their 59-- flows later on to decide how much time we waited from queueing the event 60-- until we started processing it. 61DROP VIEW IF EXISTS chrome_valid_gesture_updates; 62CREATE PERFETTO VIEW chrome_valid_gesture_updates 63AS 64SELECT 65 name, 66 EXTRACT_ARG( 67 arg_set_id, 'chrome_latency_info.trace_id') AS trace_id, 68 ts, 69 id, 70 dur 71FROM 72 {{slice_table_name}} 73WHERE 74 name = 'InputLatency::GestureScrollUpdate' 75 AND EXTRACT_ARG( 76 arg_set_id, "chrome_latency_info.is_coalesced") 77 = 0 78ORDER BY trace_id; 79 80-- Get all chrome_latency_info_for_gesture_slices where trace_ids are not -1, 81-- as those are faulty, then join with the GestureScrollUpdate table to get 82-- only slices associated with update events. 83DROP VIEW IF EXISTS chrome_flow_slices_for_gestures; 84CREATE PERFETTO VIEW chrome_flow_slices_for_gestures 85AS 86SELECT 87 s.ts, 88 EXTRACT_ARG( 89 s.arg_set_id, 'chrome_latency_info.trace_id') AS trace_id, 90 s.arg_set_id, 91 s.id, 92 s.track_id, 93 s.dur 94FROM 95 {{slice_table_name}} s 96JOIN chrome_valid_gesture_updates 97 ON 98 chrome_valid_gesture_updates.trace_id = EXTRACT_ARG( 99 s.arg_set_id, 'chrome_latency_info.trace_id') 100 AND s.ts >= chrome_valid_gesture_updates.ts 101 AND s.ts + s.dur 102 <= chrome_valid_gesture_updates.ts + chrome_valid_gesture_updates.dur 103WHERE 104 s.name = 'LatencyInfo.Flow' 105 AND trace_id != -1; 106 107-- Tie chrome_latency_info_for_gesture_slices slices to processes to avoid 108-- calculating intervals per process as multiple chrome instances can be up 109-- on system traces. 110DROP VIEW IF EXISTS chrome_flow_slices_for_gestures_tied_process; 111CREATE PERFETTO VIEW chrome_flow_slices_for_gestures_tied_process 112AS 113SELECT 114 ts, 115 trace_id, 116 arg_set_id, 117 chrome_flow_slices_for_gestures.id, 118 dur, 119 thread.upid 120FROM 121 chrome_flow_slices_for_gestures 122JOIN thread_track ON chrome_flow_slices_for_gestures.track_id = thread_track.id 123JOIN thread ON thread_track.utid = thread.utid 124 AND is_main_thread; 125 126-- Index all flows per trace_id, to get the first flow event per input 127-- GestureScrollUpdate, this will later be used to calculate the time 128-- from receiving input to the first flow event appearing. 129DROP TABLE IF EXISTS chrome_indexed_flow_per_gesture; 130CREATE PERFETTO TABLE chrome_indexed_flow_per_gesture 131AS 132SELECT 133 ts, 134 trace_id, 135 arg_set_id, 136 id, 137 ROW_NUMBER() 138 OVER ( 139 PARTITION BY trace_id, upid 140 ORDER BY 141 ts ASC 142 ) AS flow_order, 143 upid, 144 dur 145FROM 146 chrome_flow_slices_for_gestures_tied_process; 147 148-- TODO(b/235067134) all the previous views including this one are 149-- reimplementations of gesture_jank.sql with less restrictions, let's 150-- merge both of them into one script or make this script a base for the 151-- other. 152-- Get the first flow event per gesture. 153DROP VIEW IF EXISTS chrome_first_flow_per_gesture; 154CREATE PERFETTO VIEW chrome_first_flow_per_gesture 155AS 156SELECT 157 * 158FROM 159 chrome_indexed_flow_per_gesture 160WHERE 161 flow_order = 1; 162 163-- The decision for processing on the browser main thread for a frame can be 164-- instant, or delayed by the renderer in cases where the renderer needs to 165-- decide whether the touch move is an ScrollUpdate or not, and in other cases 166-- for flings, the scroll itself will be generated by the viz compositor thread 167-- on each vsync interval. 168DROP VIEW IF EXISTS chrome_categorized_first_flow_events; 169CREATE PERFETTO VIEW chrome_categorized_first_flow_events 170AS 171SELECT 172 *, 173 NOT COALESCE(( 174 SELECT 175 COUNT() 176 FROM 177 ancestor_slice(chrome_first_flow_per_gesture.id) ancestor_slices 178 WHERE 179 -- sendTouchEvent means the event wasn't delayed by the renderer 180 -- and is not a fling generated by the viz compositor thread(GPU process). 181 ancestor_slices.name = "sendTouchEvent" 182 ) 183 = 1, FALSE) AS blocked_gesture 184FROM 185 chrome_first_flow_per_gesture; 186 187-- For cases where it's not blocked, get the timestamp of input as the 188-- beginning of time we theoretically could have started processing 189-- the input event, which is the timestamp of the GestureScrollUpdate event 190-- otherwise fall back to the top level slice to check the timestamp 191-- of it's calling flow 192DROP VIEW IF EXISTS chrome_input_to_browser_interval_slice_ids; 193CREATE PERFETTO VIEW chrome_input_to_browser_interval_slice_ids 194AS 195SELECT 196 chrome_categorized_first_flow_events.id AS window_end_id, 197 chrome_categorized_first_flow_events.ts AS window_end_ts, 198 -- If blocked, get the flow_out slice's timestamp as our beginning 199 -- given that the flow_in is coming to our toplevel parent task 200 CASE 201 WHEN blocked_gesture 202 THEN 203 {{function_prefix}}PRECEDING_IO_THREAD_EVENT_FLOW_ID(chrome_categorized_first_flow_events.id) 204 ELSE 205 -- TODO(b/236590359): is selecting here better or join and ordering by? 206 -- Let's benchmark and modify accordingly. 207 ( 208 SELECT 209 chrome_gestures.id 210 FROM 211 chrome_valid_gesture_updates chrome_gestures 212 WHERE 213 chrome_gestures.trace_id = chrome_categorized_first_flow_events.trace_id 214 AND chrome_gestures.ts <= chrome_categorized_first_flow_events.ts 215 AND chrome_gestures.ts + chrome_gestures.dur >= chrome_categorized_first_flow_events.ts 216 + chrome_categorized_first_flow_events.dur 217 ) 218 END AS window_start_id, 219 blocked_gesture, 220 upid 221FROM 222 chrome_categorized_first_flow_events;