blob: 8d5d8a504561d1b6e73bc6cfa2f230c68690cb7f [file] [log] [blame]
--
-- 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;