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