blob: 36371dd1f76e7cd01b60def101c86fff54fc4aa6 [file] [log] [blame]
-- Copyright 2024 The Chromium Authors
-- Use of this source code is governed by a BSD-style license that can be
-- found in the LICENSE file.
-- Finds the start timestamp for a given slice's descendant with a given name.
-- If there are multiple descendants with a given name, the function will return
-- the first one, so it's most useful when working with a timeline broken down
-- into phases, where each subphase can happen only once.
CREATE PERFETTO FUNCTION _descendant_slice_begin(
-- Id of the parent slice.
parent_id LONG,
-- Name of the child with the desired start TS.
child_name STRING
)
-- Start timestamp of the child or NULL if it doesn't exist.
RETURNS LONG AS
SELECT
s.ts
FROM descendant_slice($parent_id) AS s
WHERE
s.name GLOB $child_name
LIMIT 1;
-- Finds the end timestamp for a given slice's descendant with a given name.
-- If there are multiple descendants with a given name, the function will return
-- the first one, so it's most useful when working with a timeline broken down
-- into phases, where each subphase can happen only once.
CREATE PERFETTO FUNCTION _descendant_slice_end(
-- Id of the parent slice.
parent_id LONG,
-- Name of the child with the desired end TS.
child_name STRING
)
-- End timestamp of the child or NULL if it doesn't exist.
RETURNS LONG AS
SELECT
CASE WHEN NOT s.dur IS -1 THEN s.ts + s.dur ELSE NULL END
FROM descendant_slice($parent_id) AS s
WHERE
s.name GLOB $child_name
LIMIT 1;
-- Checks if slice has a descendant with provided name.
CREATE PERFETTO FUNCTION _has_descendant_slice_with_name(
-- Id of the slice to check descendants of.
id LONG,
-- Name of potential descendant slice.
descendant_name STRING
)
-- Whether `descendant_name` is a name of an descendant slice.
RETURNS BOOL AS
SELECT
EXISTS(
SELECT
1
FROM descendant_slice($id)
WHERE
name = $descendant_name
LIMIT 1
);
-- Returns the presentation timestamp for a given EventLatency slice.
-- This is either the end of
-- SwapEndToPresentationCompositorFrame (if it exists),
-- the end of LatchToPresentation (if it exists),
-- the end of SwapStartToPresentation (if it exists),
-- or the end of LatchToSwapEnd (workaround in older Chrome versions).
CREATE PERFETTO FUNCTION _get_presentation_timestamp(
-- The slice id which we need the presentation timestamp for.
id LONG
)
RETURNS LONG AS
SELECT
coalesce(
_descendant_slice_end(id, 'SwapEndToPresentationCompositorFrame'),
_descendant_slice_end(id, '*ToPresentation'),
_descendant_slice_end(id, 'LatchToSwapEnd')
)
FROM slice
WHERE
$id = id;
-- All EventLatency slices.
CREATE PERFETTO TABLE chrome_event_latencies (
-- Slice Id for the EventLatency scroll event.
id LONG,
-- Slice name.
name STRING,
-- The start timestamp of the scroll.
ts TIMESTAMP,
-- The duration of the scroll.
dur DURATION,
-- The id of the scroll update event (aka LatencyInfo.ID).
scroll_update_id LONG,
-- The id of the first frame (pre-surface aggregation) which included the
-- scroll update and was presented. NULL if:
-- (1) the event is not a scroll update (`event_type` is NOT
-- GESTURE_SCROLL_UPDATE, FIRST_GESTURE_SCROLL_UPDATE, or
-- INERTIAL_GESTURE_SCROLL_UPDATE),
-- (2) the scroll update wasn't presented (e.g. it was an overscroll) or
-- (3) the trace comes from an old Chrome version (https://crrev.com/c/6185817
-- was first included in version 134.0.6977.0 and was cherry-picked in
-- version 133.0.6943.33).
surface_frame_trace_id LONG,
-- The id of the first frame (post-surface aggregation) which included the
-- scroll update and was presented. NULL if:
-- (1) the event is not a scroll update (`event_type` is NOT
-- GESTURE_SCROLL_UPDATE, FIRST_GESTURE_SCROLL_UPDATE, or
-- INERTIAL_GESTURE_SCROLL_UPDATE),
-- (2) the scroll update wasn't presented (e.g. it was an overscroll) or
-- (3) the trace comes from an old Chrome version (https://crrev.com/c/6185817
-- was first included in version 134.0.6977.0 and was cherry-picked in
-- version 133.0.6943.33).
display_trace_id LONG,
-- Whether this input event was presented.
is_presented BOOL,
-- EventLatency event type.
event_type STRING,
-- Perfetto track this slice is found on.
track_id LONG,
-- Vsync interval (in milliseconds).
vsync_interval_ms DOUBLE,
-- Whether the corresponding frame is janky based on the
-- Event.ScrollJank.DelayedFramesPercentage.FixedWindow metric.
is_janky_scrolled_frame BOOL,
-- Whether the corresponding frame is janky based on the
-- Event.ScrollJank.DelayedFramesPercentage.FixedWindow3 metric.
is_janky_scrolled_frame_v3 BOOL,
-- Timestamp of the BufferAvailableToBufferReady substage.
buffer_available_timestamp LONG,
-- Timestamp of the BufferReadyToLatch substage.
buffer_ready_timestamp LONG,
-- Timestamp of the LatchToSwapEnd substage (or LatchToPresentation as a
-- fallback).
latch_timestamp LONG,
-- Timestamp of the SwapEndToPresentationCompositorFrame substage.
swap_end_timestamp LONG,
-- Frame presentation timestamp aka the timestamp of the
-- SwapEndToPresentationCompositorFrame substage.
-- TODO(b/341047059): temporarily use LatchToSwapEnd as a workaround if
-- SwapEndToPresentationCompositorFrame is missing due to b/247542163.
presentation_timestamp LONG
) AS
SELECT
slice.id,
slice.name,
slice.ts,
slice.dur,
extract_arg(arg_set_id, 'event_latency.event_latency_id') AS scroll_update_id,
extract_arg(arg_set_id, 'event_latency.surface_frame_trace_id') AS surface_frame_trace_id,
extract_arg(arg_set_id, 'event_latency.display_trace_id') AS display_trace_id,
_has_descendant_slice_with_name(slice.id, 'SubmitCompositorFrameToPresentationCompositorFrame') AS is_presented,
extract_arg(arg_set_id, 'event_latency.event_type') AS event_type,
slice.track_id,
extract_arg(arg_set_id, 'event_latency.vsync_interval_ms') AS vsync_interval_ms,
coalesce(extract_arg(arg_set_id, 'event_latency.is_janky_scrolled_frame'), 0) AS is_janky_scrolled_frame,
coalesce(extract_arg(arg_set_id, 'event_latency.is_janky_scrolled_frame_v3'), 0) AS is_janky_scrolled_frame_v3,
_descendant_slice_begin(slice.id, 'BufferAvailableToBufferReady') AS buffer_available_timestamp,
_descendant_slice_begin(slice.id, 'BufferReadyToLatch') AS buffer_ready_timestamp,
coalesce(
_descendant_slice_begin(slice.id, 'LatchToSwapEnd'),
_descendant_slice_begin(slice.id, 'LatchToPresentation')
) AS latch_timestamp,
_descendant_slice_begin(slice.id, 'SwapEndToPresentationCompositorFrame') AS swap_end_timestamp,
_get_presentation_timestamp(slice.id) AS presentation_timestamp
FROM slice
WHERE
name = 'EventLatency';
-- All scroll-related events (frames) including gesture scroll updates, begins
-- and ends with respective scroll ids and start/end timestamps, regardless of
-- being presented. This includes pinches that were presented. See b/315761896
-- for context on pinches.
CREATE PERFETTO TABLE chrome_gesture_scroll_updates (
-- Slice Id for the EventLatency scroll event.
id LONG,
-- Slice name.
name STRING,
-- The start timestamp of the scroll.
ts TIMESTAMP,
-- The duration of the scroll.
dur DURATION,
-- The id of the scroll update event.
scroll_update_id LONG,
-- Whether this input event was presented.
is_presented BOOL,
-- EventLatency event type.
event_type STRING,
-- Perfetto track this slice is found on.
track_id LONG,
-- Vsync interval (in milliseconds).
vsync_interval_ms DOUBLE,
-- Whether the corresponding frame is janky based on the
-- Event.ScrollJank.DelayedFramesPercentage.FixedWindow metric.
is_janky BOOL,
-- Whether the corresponding frame is janky based on the
-- Event.ScrollJank.DelayedFramesPercentage.FixedWindow3 metric.
is_janky_v3 BOOL,
-- Timestamp of the BufferAvailableToBufferReady substage.
buffer_available_timestamp LONG,
-- Timestamp of the BufferReadyToLatch substage.
buffer_ready_timestamp LONG,
-- Timestamp of the LatchToSwapEnd substage (or LatchToPresentation as a
-- fallback).
latch_timestamp LONG,
-- Timestamp of the SwapEndToPresentationCompositorFrame substage.
swap_end_timestamp LONG,
-- Frame presentation timestamp aka the timestamp of the
-- SwapEndToPresentationCompositorFrame substage.
-- TODO(b/341047059): temporarily use LatchToSwapEnd as a workaround if
-- SwapEndToPresentationCompositorFrame is missing due to b/247542163.
presentation_timestamp LONG,
-- The id of the scroll.
scroll_id LONG
) AS
-- To compute scroll id, we first mark all of the FIRST_GESTURE_SCROLL_UPDATE events
-- (or the first scroll update in the trace) as the points where scroll id should be
-- incremented and then use the cumulative sum as the scroll id.
WITH
updates_without_scroll_ids AS (
SELECT
id,
name,
ts,
dur,
scroll_update_id,
is_presented,
event_type,
track_id,
vsync_interval_ms,
is_janky_scrolled_frame AS is_janky,
is_janky_scrolled_frame_v3 AS is_janky_v3,
buffer_available_timestamp,
buffer_ready_timestamp,
latch_timestamp,
swap_end_timestamp,
presentation_timestamp,
(
event_type = 'FIRST_GESTURE_SCROLL_UPDATE' OR row_number() OVER (ORDER BY ts) = 1
) AS is_first_update_in_scroll
FROM chrome_event_latencies
WHERE
event_type IN ('GESTURE_SCROLL_UPDATE', 'FIRST_GESTURE_SCROLL_UPDATE', 'INERTIAL_GESTURE_SCROLL_UPDATE')
OR (
-- Pinches are only relevant if the frame was presented.
event_type GLOB '*GESTURE_PINCH_UPDATE'
AND is_presented
)
)
SELECT
id,
name,
ts,
dur,
scroll_update_id,
is_presented,
event_type,
track_id,
vsync_interval_ms,
is_janky,
is_janky_v3,
buffer_available_timestamp,
buffer_ready_timestamp,
latch_timestamp,
swap_end_timestamp,
presentation_timestamp,
coalesce(
sum(cast_int!(is_first_update_in_scroll)) OVER (ORDER BY ts ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
0
) AS scroll_id
FROM updates_without_scroll_ids;