| -- |
| -- Copyright 2022 The Android Open Source Project |
| -- |
| -- Licensed under the Apache License, Version 2.0 (the "License"); |
| -- you may not use this file except in compliance with the License. |
| -- You may obtain a copy of the License at |
| -- |
| -- https://www.apache.org/licenses/LICENSE-2.0 |
| -- |
| -- Unless required by applicable law or agreed to in writing, software |
| -- distributed under the License is distributed on an "AS IS" BASIS, |
| -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| -- See the License for the specific language governing permissions and |
| -- limitations under the License. |
| -- |
| -- WARNING: This metric should not be used as a source of truth. It is under |
| -- active development and the values & meaning might change without |
| -- notice. |
| |
| SELECT CREATE_FUNCTION( |
| -- Given a slice id of an event, get timestamp of the most recent flow |
| -- event on the Chrome IO thread that preceded this slice. |
| -- This helps us identify the last flow event on the IO thread before |
| -- letting the browser main thread be aware of input. |
| -- We need this for flings (generated by the GPU process) and blocked |
| -- touch moves that are forwarded from the renderer. |
| '{{function_prefix}}PRECEDING_IO_THREAD_EVENT_FLOW_ID(id LONG)', |
| -- Returning the slice id for the flow_out on the chrome IO thread. |
| 'LONG', |
| 'SELECT MAX(flow.slice_out) AS id |
| FROM |
| PRECEDING_FLOW(($id)) flow'); |
| |
| SELECT CREATE_FUNCTION( |
| '{{function_prefix}}GET_MOJO_PARENT_INTERFACE_TAG(id LONG)', |
| 'STRING', |
| 'SELECT |
| interface_name |
| FROM |
| (SELECT MAX(mojo.id), |
| interface_name |
| FROM ((SELECT id FROM ancestor_slice(($id)) |
| UNION |
| SELECT slice.id as id FROM PRECEDING_FLOW(($id)) flow |
| JOIN slice ON flow.slice_out = slice.id) candidates |
| JOIN chrome_mojo_slices_tbl mojo |
| ON mojo.id = candidates.id |
| OR (SELECT COUNT() FROM ancestor_slice(candidates.id) parents |
| WHERE parents.id = mojo.id) > 0))' |
| ); |
| |
| SELECT CREATE_FUNCTION( |
| '{{function_prefix}}GET_SCROLL_TYPE(blocked_gesture BOOL, mojo_interface_tag STRING)', |
| 'STRING', |
| 'SELECT |
| CASE WHEN ($blocked_gesture) |
| THEN (SELECT |
| CASE WHEN ($mojo_interface_tag) = "viz.mojom.BeginFrameObserver" |
| THEN "fling" |
| WHEN ($mojo_interface_tag) = "blink.mojom.WidgetInputHandler" |
| THEN "blocking_touch_move" |
| ELSE "unknown" END) |
| ELSE "regular" END AS delay_type'); |
| |
| -- Get all InputLatency::GestureScrollUpdate events, to use their |
| -- flows later on to decide how much time we waited from queueing the event |
| -- until we started processing it. |
| DROP VIEW IF EXISTS chrome_valid_gesture_updates; |
| CREATE VIEW chrome_valid_gesture_updates |
| AS |
| SELECT |
| name, |
| EXTRACT_ARG( |
| arg_set_id, 'chrome_latency_info.trace_id') AS trace_id, |
| ts, |
| id, |
| dur |
| FROM |
| {{slice_table_name}} |
| WHERE |
| name = 'InputLatency::GestureScrollUpdate' |
| AND EXTRACT_ARG( |
| arg_set_id, "chrome_latency_info.is_coalesced") |
| = 0 |
| ORDER BY trace_id; |
| |
| -- Get all chrome_latency_info_for_gesture_slices where trace_ids are not -1, |
| -- as those are faulty, then join with the GestureScrollUpdate table to get |
| -- only slices associated with update events. |
| DROP VIEW IF EXISTS chrome_flow_slices_for_gestures; |
| CREATE VIEW chrome_flow_slices_for_gestures |
| AS |
| SELECT |
| s.ts, |
| EXTRACT_ARG( |
| s.arg_set_id, 'chrome_latency_info.trace_id') AS trace_id, |
| s.arg_set_id, |
| s.id, |
| s.track_id, |
| s.dur |
| FROM |
| {{slice_table_name}} s |
| JOIN chrome_valid_gesture_updates |
| ON |
| chrome_valid_gesture_updates.trace_id = EXTRACT_ARG( |
| s.arg_set_id, 'chrome_latency_info.trace_id') |
| AND s.ts >= chrome_valid_gesture_updates.ts |
| AND s.ts + s.dur |
| <= chrome_valid_gesture_updates.ts + chrome_valid_gesture_updates.dur |
| WHERE |
| s.name = 'LatencyInfo.Flow' |
| AND trace_id != -1; |
| |
| -- Tie chrome_latency_info_for_gesture_slices slices to processes to avoid |
| -- calculating intervals per process as multiple chrome instances can be up |
| -- on system traces. |
| DROP VIEW IF EXISTS chrome_flow_slices_for_gestures_tied_process; |
| CREATE VIEW chrome_flow_slices_for_gestures_tied_process |
| AS |
| SELECT |
| ts, |
| trace_id, |
| arg_set_id, |
| chrome_flow_slices_for_gestures.id, |
| dur, |
| thread.upid |
| FROM |
| chrome_flow_slices_for_gestures |
| JOIN thread_track ON chrome_flow_slices_for_gestures.track_id = thread_track.id |
| JOIN thread ON thread_track.utid = thread.utid |
| AND is_main_thread; |
| |
| -- Index all flows per trace_id, to get the first flow event per input |
| -- GestureScrollUpdate, this will later be used to calculate the time |
| -- from receiving input to the first flow event appearing. |
| DROP TABLE IF EXISTS chrome_indexed_flow_per_gesture; |
| CREATE TABLE chrome_indexed_flow_per_gesture |
| AS |
| SELECT |
| ts, |
| trace_id, |
| arg_set_id, |
| id, |
| ROW_NUMBER() |
| OVER ( |
| PARTITION BY trace_id, upid |
| ORDER BY |
| ts ASC |
| ) AS flow_order, |
| upid, |
| dur |
| FROM |
| chrome_flow_slices_for_gestures_tied_process; |
| |
| -- TODO(b/235067134) all the previous views including this one are |
| -- reimplementations of gesture_jank.sql with less restrictions, let's |
| -- merge both of them into one script or make this script a base for the |
| -- other. |
| -- Get the first flow event per gesture. |
| DROP VIEW IF EXISTS chrome_first_flow_per_gesture; |
| CREATE VIEW chrome_first_flow_per_gesture |
| AS |
| SELECT |
| * |
| FROM |
| chrome_indexed_flow_per_gesture |
| WHERE |
| flow_order = 1; |
| |
| |
| |
| -- The decision for processing on the browser main thread for a frame can be |
| -- instant, or delayed by the renderer in cases where the renderer needs to |
| -- decide whether the touch move is an ScrollUpdate or not, and in other cases |
| -- for flings, the scroll itself will be generated by the viz compositor thread |
| -- on each vsync interval. |
| DROP VIEW IF EXISTS chrome_categorized_first_flow_events; |
| CREATE VIEW chrome_categorized_first_flow_events |
| AS |
| SELECT |
| *, |
| NOT COALESCE(( |
| SELECT |
| COUNT() |
| FROM |
| ancestor_slice(chrome_first_flow_per_gesture.id) ancestor_slices |
| WHERE |
| -- sendTouchEvent means the event wasn't delayed by the renderer |
| -- and is not a fling generated by the viz compositor thread(GPU process). |
| ancestor_slices.name = "sendTouchEvent" |
| ) |
| = 1, FALSE) AS blocked_gesture |
| FROM |
| chrome_first_flow_per_gesture; |
| |
| -- For cases where it's not blocked, get the timestamp of input as the |
| -- beginning of time we theoretically could have started processing |
| -- the input event, which is the timestamp of the GestureScrollUpdate event |
| -- otherwise fall back to the top level slice to check the timestamp |
| -- of it's calling flow |
| DROP VIEW IF EXISTS chrome_input_to_browser_interval_slice_ids; |
| CREATE VIEW chrome_input_to_browser_interval_slice_ids |
| AS |
| SELECT |
| chrome_categorized_first_flow_events.id AS window_end_id, |
| chrome_categorized_first_flow_events.ts AS window_end_ts, |
| -- If blocked, get the flow_out slice's timestamp as our beginning |
| -- given that the flow_in is coming to our toplevel parent task |
| CASE |
| WHEN blocked_gesture |
| THEN |
| {{function_prefix}}PRECEDING_IO_THREAD_EVENT_FLOW_ID(chrome_categorized_first_flow_events.id) |
| ELSE |
| -- TODO(b/236590359): is selecting here better or join and ordering by? |
| -- Let's benchmark and modify accordingly. |
| ( |
| SELECT |
| chrome_gestures.id |
| FROM |
| chrome_valid_gesture_updates chrome_gestures |
| WHERE |
| chrome_gestures.trace_id = chrome_categorized_first_flow_events.trace_id |
| AND chrome_gestures.ts <= chrome_categorized_first_flow_events.ts |
| AND chrome_gestures.ts + chrome_gestures.dur >= chrome_categorized_first_flow_events.ts |
| + chrome_categorized_first_flow_events.dur |
| ) |
| END AS window_start_id, |
| blocked_gesture, |
| upid |
| FROM |
| chrome_categorized_first_flow_events; |