|  | -- Copyright 2023 The Chromium Authors | 
|  | -- Use of this source code is governed by a BSD-style license that can be | 
|  | -- found in the LICENSE file. | 
|  |  | 
|  | INCLUDE PERFETTO MODULE chrome.event_latency; | 
|  |  | 
|  | INCLUDE PERFETTO MODULE chrome.graphics_pipeline; | 
|  |  | 
|  | INCLUDE PERFETTO MODULE chrome.input; | 
|  |  | 
|  | INCLUDE PERFETTO MODULE chrome.scroll_jank.scroll_offsets; | 
|  |  | 
|  | INCLUDE PERFETTO MODULE chrome.scroll_jank.utils; | 
|  |  | 
|  | -- Ties together input (`LatencyInfo.Flow`) and frame (`Graphics.Pipeline`) | 
|  | -- trace events. Only covers input events of the `GESTURE_SCROLL_UPDATE_EVENT` | 
|  | -- type. | 
|  | CREATE PERFETTO TABLE chrome_scroll_update_refs ( | 
|  | -- Id of the Chrome input pipeline (`LatencyInfo.Flow`). | 
|  | scroll_update_latency_id LONG, | 
|  | -- Id of the touch move input corresponding to this scroll update. | 
|  | touch_move_latency_id LONG, | 
|  | -- Id of the `EventLatency` of the frame that the input was presented in. | 
|  | presentation_latency_id LONG, | 
|  | -- Id of the frame pipeline (`Graphics.Pipeline`), pre-surface aggregation. | 
|  | surface_frame_id LONG, | 
|  | -- Id of the frame pipeline (`Graphics.Pipeline`), post-surface aggregation. | 
|  | display_trace_id LONG | 
|  | ) AS | 
|  | SELECT | 
|  | scroll_update.latency_id AS scroll_update_latency_id, | 
|  | chrome_touch_move_to_scroll_update.touch_move_latency_id, | 
|  | coalesce(chrome_coalesced_inputs.presented_latency_id, scroll_update.latency_id) AS presentation_latency_id, | 
|  | chrome_graphics_pipeline_inputs_to_surface_frames.surface_frame_trace_id AS surface_frame_id, | 
|  | chrome_surface_frame_id_to_first_display_id.display_trace_id | 
|  | FROM chrome_inputs AS scroll_update | 
|  | LEFT JOIN chrome_graphics_pipeline_inputs_to_surface_frames | 
|  | USING (latency_id) | 
|  | LEFT JOIN chrome_surface_frame_id_to_first_display_id | 
|  | ON chrome_surface_frame_id_to_first_display_id.surface_frame_trace_id = chrome_graphics_pipeline_inputs_to_surface_frames.surface_frame_trace_id | 
|  | LEFT JOIN chrome_touch_move_to_scroll_update | 
|  | ON chrome_touch_move_to_scroll_update.scroll_update_latency_id = scroll_update.latency_id | 
|  | LEFT JOIN chrome_coalesced_inputs | 
|  | ON chrome_coalesced_inputs.coalesced_latency_id = scroll_update.latency_id | 
|  | WHERE | 
|  | scroll_update.input_type = 'GESTURE_SCROLL_UPDATE_EVENT'; | 
|  |  | 
|  | -- Timestamps and other related information for events during the | 
|  | -- input-associated (before inputs are coalesced into a frame) stages of a | 
|  | -- scroll. | 
|  | CREATE PERFETTO TABLE _scroll_update_input_timestamps_and_metadata AS | 
|  | SELECT | 
|  | refs.scroll_update_latency_id AS id, | 
|  | refs.presentation_latency_id AS presented_in_frame_id, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | chrome_event_latency.scroll_id, | 
|  | chrome_event_latency.is_presented, | 
|  | chrome_event_latency.is_janky, | 
|  | chrome_event_latency.is_janky_v3, | 
|  | chrome_event_latency.event_type = 'INERTIAL_GESTURE_SCROLL_UPDATE' AS is_inertial, | 
|  | chrome_event_latency.event_type = 'FIRST_GESTURE_SCROLL_UPDATE' AS is_first_scroll_update_in_scroll, | 
|  | chrome_event_latency.ts AS generation_ts, | 
|  | chrome_android_input.input_reader_processing_end_ts, | 
|  | chrome_android_input.input_dispatcher_processing_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | touch_move_received_step.slice_id AS touch_move_received_slice_id, | 
|  | touch_move_received_step.ts AS touch_move_received_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | touch_move_processed_step.slice_id AS touch_move_processed_slice_id, | 
|  | touch_move_processed_step.ts AS touch_move_processed_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | scroll_update_created_step.slice_id AS scroll_update_created_slice_id, | 
|  | scroll_update_created_step.utid AS browser_utid, | 
|  | scroll_update_created_step.ts AS scroll_update_created_ts, | 
|  | scroll_update_created_step.ts + scroll_update_created_step.dur AS scroll_update_created_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_dispatch_step.slice_id AS compositor_dispatch_slice_id, | 
|  | compositor_dispatch_step.task_start_time_ts AS compositor_dispatch_task_ts, | 
|  | compositor_dispatch_step.ts AS compositor_dispatch_ts, | 
|  | compositor_dispatch_step.ts + compositor_dispatch_step.dur AS compositor_dispatch_end_ts, | 
|  | compositor_dispatch_step.utid AS compositor_utid, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_coalesced_input_handled_step.slice_id AS compositor_coalesced_input_handled_slice_id, | 
|  | compositor_coalesced_input_handled_step.ts AS compositor_coalesced_input_handled_ts, | 
|  | compositor_coalesced_input_handled_step.ts + compositor_coalesced_input_handled_step.dur AS compositor_coalesced_input_handled_end_ts | 
|  | FROM chrome_scroll_update_refs AS refs | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_gesture_scroll_updates AS chrome_event_latency | 
|  | ON chrome_event_latency.scroll_update_id = refs.scroll_update_latency_id | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_dispatch_android_input_event_to_touch_move | 
|  | ON refs.touch_move_latency_id = chrome_dispatch_android_input_event_to_touch_move.touch_move_latency_id | 
|  | LEFT JOIN chrome_android_input | 
|  | ON chrome_android_input.android_input_id = chrome_dispatch_android_input_event_to_touch_move.android_input_id | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_input_pipeline_steps AS touch_move_received_step | 
|  | ON refs.touch_move_latency_id = touch_move_received_step.latency_id | 
|  | AND touch_move_received_step.step = 'STEP_SEND_INPUT_EVENT_UI' | 
|  | AND touch_move_received_step.input_type = 'TOUCH_MOVE_EVENT' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_input_pipeline_steps AS touch_move_processed_step | 
|  | ON touch_move_processed_step.latency_id = refs.touch_move_latency_id | 
|  | AND touch_move_processed_step.step = 'STEP_TOUCH_EVENT_HANDLED' | 
|  | AND touch_move_processed_step.input_type = 'TOUCH_MOVE_EVENT' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_input_pipeline_steps AS scroll_update_created_step | 
|  | ON scroll_update_created_step.latency_id = refs.scroll_update_latency_id | 
|  | AND scroll_update_created_step.step = 'STEP_SEND_INPUT_EVENT_UI' | 
|  | AND scroll_update_created_step.input_type = 'GESTURE_SCROLL_UPDATE_EVENT' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_input_pipeline_steps AS compositor_dispatch_step | 
|  | ON compositor_dispatch_step.latency_id = refs.scroll_update_latency_id | 
|  | AND compositor_dispatch_step.step = 'STEP_HANDLE_INPUT_EVENT_IMPL' | 
|  | AND compositor_dispatch_step.input_type = 'GESTURE_SCROLL_UPDATE_EVENT' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_input_pipeline_steps AS compositor_coalesced_input_handled_step | 
|  | ON compositor_coalesced_input_handled_step.latency_id = refs.scroll_update_latency_id | 
|  | AND compositor_coalesced_input_handled_step.step = 'STEP_DID_HANDLE_INPUT_AND_OVERSCROLL' | 
|  | AND compositor_coalesced_input_handled_step.input_type = 'GESTURE_SCROLL_UPDATE_EVENT'; | 
|  |  | 
|  | -- Timestamps and durations for the input-associated (before coalescing inputs | 
|  | -- into a frame) stages of a scroll. | 
|  | CREATE PERFETTO TABLE chrome_scroll_update_input_pipeline ( | 
|  | -- Id of the `LatencyInfo.Flow` slices corresponding to this scroll event. | 
|  | id LONG, | 
|  | -- Id of the scroll this scroll update belongs to. | 
|  | scroll_id LONG, | 
|  | -- Id of the frame that this input was presented in. Can be joined with | 
|  | -- `chrome_scroll_update_frame_pipeline.id`. | 
|  | presented_in_frame_id LONG, | 
|  | -- Whether this input event was presented. | 
|  | is_presented BOOL, | 
|  | -- Whether the corresponding frame is janky based on the | 
|  | -- Event.ScrollJank.DelayedFramesPercentage.FixedWindow metric. This comes | 
|  | -- directly from `perfetto.protos.EventLatency.is_janky_scrolled_frame`. | 
|  | is_janky BOOL, | 
|  | -- Whether the corresponding frame is janky based on the | 
|  | -- Event.ScrollJank.DelayedFramesPercentage.FixedWindow3 metric. This comes | 
|  | -- directly from `perfetto.protos.EventLatency.is_janky_scrolled_frame_v3`. | 
|  | is_janky_v3 BOOL, | 
|  | -- Whether the corresponding scroll is inertial (fling). | 
|  | -- If this is `true`, "generation" and "touch_move" related timestamps and | 
|  | -- durations will be null. | 
|  | is_inertial BOOL, | 
|  | -- Whether this is the first update in a scroll. | 
|  | -- First scroll update can never be janky. | 
|  | is_first_scroll_update_in_scroll BOOL, | 
|  | -- Whether this is the first input that was presented in frame | 
|  | -- `presented_in_frame_id`. | 
|  | is_first_scroll_update_in_frame BOOL, | 
|  | -- Input generation timestamp (from the Android system). | 
|  | generation_ts TIMESTAMP, | 
|  | -- End timestamp for the InputReader step (see android_input.sql). | 
|  | -- Only populated when atrace 'input' category is enabled. | 
|  | input_reader_processing_end_ts TIMESTAMP, | 
|  | -- End timestamp for the InputDispatcher step (see android_input.sql). | 
|  | -- Only populated when atrace 'input' category is enabled. | 
|  | input_dispatcher_processing_end_ts TIMESTAMP, | 
|  | -- Duration from input generation to when the browser received the input. | 
|  | generation_to_browser_main_dur DURATION, | 
|  | -- Utid for the browser main thread. | 
|  | browser_utid LONG, | 
|  | -- Slice id for the `STEP_SEND_INPUT_EVENT_UI` slice for the touch move. | 
|  | touch_move_received_slice_id LONG, | 
|  | -- Timestamp for the `STEP_SEND_INPUT_EVENT_UI` slice for the touch move. | 
|  | touch_move_received_ts TIMESTAMP, | 
|  | -- Duration for processing  a `TouchMove` event. | 
|  | touch_move_processing_dur DURATION, | 
|  | -- Slice id for the `STEP_SEND_INPUT_EVENT_UI` slice for the gesture scroll. | 
|  | scroll_update_created_slice_id LONG, | 
|  | -- Timestamp for the `STEP_SEND_INPUT_EVENT_UI` slice for the gesture scroll. | 
|  | scroll_update_created_ts TIMESTAMP, | 
|  | -- Duration for creating a `GestureScrollUpdate` from a `TouchMove` event. | 
|  | scroll_update_processing_dur DURATION, | 
|  | -- End timestamp for the `STEP_SEND_INPUT_EVENT_UI` slice for the above. | 
|  | scroll_update_created_end_ts TIMESTAMP, | 
|  | -- Duration between the browser and compositor dispatch. | 
|  | browser_to_compositor_delay_dur DURATION, | 
|  | -- Utid for the renderer compositor thread. | 
|  | compositor_utid LONG, | 
|  | -- Slice id for the `STEP_HANDLE_INPUT_EVENT_IMPL` slice. | 
|  | compositor_dispatch_slice_id LONG, | 
|  | -- Timestamp for the `STEP_HANDLE_INPUT_EVENT_IMPL` slice or the | 
|  | -- containing task (if available). | 
|  | compositor_dispatch_ts TIMESTAMP, | 
|  | -- Duration for the compositor dispatch itself. | 
|  | compositor_dispatch_dur DURATION, | 
|  | -- End timestamp for the `STEP_HANDLE_INPUT_EVENT_IMPL` slice. | 
|  | compositor_dispatch_end_ts TIMESTAMP, | 
|  | -- Duration between compositor dispatch and coalescing input. | 
|  | compositor_dispatch_to_coalesced_input_handled_dur DURATION, | 
|  | -- Slice id for the `STEP_DID_HANDLE_INPUT_AND_OVERSCROLL` slice. | 
|  | compositor_coalesced_input_handled_slice_id LONG, | 
|  | -- Timestamp for the `STEP_DID_HANDLE_INPUT_AND_OVERSCROLL` slice. | 
|  | compositor_coalesced_input_handled_ts TIMESTAMP, | 
|  | -- Duration for the `STEP_DID_HANDLE_INPUT_AND_OVERSCROLL` slice. | 
|  | compositor_coalesced_input_handled_dur DURATION, | 
|  | -- End timestamp for the `STEP_DID_HANDLE_INPUT_AND_OVERSCROLL` slice. | 
|  | compositor_coalesced_input_handled_end_ts TIMESTAMP | 
|  | ) AS | 
|  | WITH | 
|  | processed_timestamps_and_metadata AS ( | 
|  | SELECT | 
|  | id, | 
|  | scroll_id, | 
|  | presented_in_frame_id, | 
|  | is_presented, | 
|  | is_janky, | 
|  | is_janky_v3, | 
|  | is_inertial, | 
|  | is_first_scroll_update_in_scroll, | 
|  | row_number() OVER (PARTITION BY presented_in_frame_id ORDER BY generation_ts ASC) = 1 AS is_first_scroll_update_in_frame, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | browser_utid, | 
|  | touch_move_received_slice_id, | 
|  | -- Timestamps | 
|  | generation_ts, | 
|  | input_reader_processing_end_ts, | 
|  | input_dispatcher_processing_end_ts, | 
|  | touch_move_received_ts, | 
|  | -- TODO(b:385160424): this is a workaround for cases when | 
|  | -- generation time is later than the input time. | 
|  | max( | 
|  | iif( | 
|  | is_inertial AND touch_move_received_ts IS NULL, | 
|  | scroll_update_created_ts, | 
|  | touch_move_received_ts | 
|  | ), | 
|  | generation_ts | 
|  | ) AS browser_main_received_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | scroll_update_created_slice_id, | 
|  | -- Timestamps | 
|  | scroll_update_created_ts, | 
|  | scroll_update_created_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | compositor_utid, | 
|  | compositor_dispatch_slice_id, | 
|  | -- Timestamps | 
|  | coalesce(compositor_dispatch_task_ts, compositor_dispatch_ts) AS compositor_dispatch_ts, | 
|  | compositor_dispatch_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | compositor_coalesced_input_handled_slice_id, | 
|  | -- Timestamps | 
|  | compositor_coalesced_input_handled_ts, | 
|  | compositor_coalesced_input_handled_end_ts | 
|  | FROM _scroll_update_input_timestamps_and_metadata | 
|  | ) | 
|  | SELECT | 
|  | id, | 
|  | scroll_id, | 
|  | presented_in_frame_id, | 
|  | is_presented, | 
|  | is_janky, | 
|  | is_janky_v3, | 
|  | is_inertial, | 
|  | is_first_scroll_update_in_scroll, | 
|  | is_first_scroll_update_in_frame, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | -- No applicable slice id (duration between two threads). | 
|  | generation_ts, | 
|  | input_reader_processing_end_ts, | 
|  | input_dispatcher_processing_end_ts, | 
|  | -- Flings don't have a touch move event so make GenerationToBrowserMain span | 
|  | -- all the way to the creation of the gesture scroll update. | 
|  | browser_main_received_ts - generation_ts AS generation_to_browser_main_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | browser_utid, | 
|  | touch_move_received_slice_id, | 
|  | touch_move_received_ts, | 
|  | scroll_update_created_ts - max(touch_move_received_ts, generation_ts) AS touch_move_processing_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `browser_utid`. | 
|  | scroll_update_created_slice_id, | 
|  | scroll_update_created_ts, | 
|  | scroll_update_created_end_ts - scroll_update_created_ts AS scroll_update_processing_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | -- No applicable slice id (duration between two threads). | 
|  | scroll_update_created_end_ts, | 
|  | -- TODO(b:385161677): use the start | 
|  | -- of the STEP_SEND_DISPATCH_EVENT_MOJO_MESSAGE step | 
|  | -- instead of scroll_update_created_end_ts. | 
|  | max(compositor_dispatch_ts, scroll_update_created_end_ts) - scroll_update_created_end_ts AS browser_to_compositor_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_utid, | 
|  | compositor_dispatch_slice_id, | 
|  | compositor_dispatch_ts, | 
|  | compositor_dispatch_end_ts - compositor_dispatch_ts AS compositor_dispatch_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | -- No applicable slice id (duration between two slices). | 
|  | compositor_dispatch_end_ts, | 
|  | -- TODO(b:380868337): This is sometimes negative; check/fix this. | 
|  | compositor_coalesced_input_handled_ts - compositor_dispatch_end_ts AS compositor_dispatch_to_coalesced_input_handled_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | compositor_coalesced_input_handled_slice_id, | 
|  | compositor_coalesced_input_handled_ts, | 
|  | compositor_coalesced_input_handled_end_ts - compositor_coalesced_input_handled_ts AS compositor_coalesced_input_handled_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_coalesced_input_handled_end_ts | 
|  | FROM processed_timestamps_and_metadata; | 
|  |  | 
|  | -- Timestamps and other related information for events during the | 
|  | -- frame-associated (after inputs are coalesced into a frame) stages of a | 
|  | -- scroll. | 
|  | CREATE PERFETTO TABLE _scroll_update_frame_timestamps_and_metadata AS | 
|  | SELECT | 
|  | refs.scroll_update_latency_id AS id, | 
|  | refs.display_trace_id, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | chrome_event_latency.vsync_interval_ms AS vsync_interval_ms, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_resample_step.slice_id AS compositor_resample_slice_id, | 
|  | compositor_resample_step.task_start_time_ts AS compositor_resample_task_ts, | 
|  | compositor_resample_step.ts AS compositor_resample_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_receive_begin_frame_step.id AS compositor_receive_begin_frame_slice_id, | 
|  | compositor_receive_begin_frame_step.task_start_time_ts AS compositor_receive_begin_frame_task_ts, | 
|  | compositor_receive_begin_frame_step.ts AS compositor_receive_begin_frame_ts, | 
|  | -- | 
|  | compositor_generate_compositor_frame_step.id AS compositor_generate_compositor_frame_slice_id, | 
|  | compositor_generate_compositor_frame_step.task_start_time_ts AS compositor_generate_compositor_frame_task_ts, | 
|  | compositor_generate_compositor_frame_step.ts AS compositor_generate_compositor_frame_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | compositor_submit_compositor_frame_step.id AS compositor_submit_compositor_frame_slice_id, | 
|  | compositor_submit_compositor_frame_step.ts AS compositor_submit_compositor_frame_ts, | 
|  | compositor_submit_compositor_frame_step.ts + compositor_submit_compositor_frame_step.dur AS compositor_submit_compositor_frame_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_receive_compositor_frame_step.id AS viz_receive_compositor_frame_slice_id, | 
|  | viz_receive_compositor_frame_step.task_start_time_ts AS viz_receive_compositor_frame_task_ts, | 
|  | viz_receive_compositor_frame_step.ts AS viz_receive_compositor_frame_ts, | 
|  | viz_receive_compositor_frame_step.ts + viz_receive_compositor_frame_step.dur AS viz_receive_compositor_frame_end_ts, | 
|  | viz_receive_compositor_frame_step.utid AS viz_compositor_utid, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_draw_and_swap_step.id AS viz_draw_and_swap_slice_id, | 
|  | viz_draw_and_swap_step.task_start_time_ts AS viz_draw_and_swap_task_ts, | 
|  | viz_draw_and_swap_step.ts AS viz_draw_and_swap_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_send_buffer_swap_step.id AS viz_send_buffer_swap_slice_id, | 
|  | viz_send_buffer_swap_step.ts + viz_send_buffer_swap_step.dur AS viz_send_buffer_swap_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_swap_buffers_step.id AS viz_swap_buffers_slice_id, | 
|  | viz_swap_buffers_step.task_start_time_ts AS viz_swap_buffers_task_ts, | 
|  | viz_swap_buffers_step.ts AS viz_swap_buffers_ts, | 
|  | viz_swap_buffers_step.ts + viz_swap_buffers_step.dur AS viz_swap_buffers_end_ts, | 
|  | viz_swap_buffers_step.utid AS viz_gpu_thread_utid, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | chrome_event_latency.buffer_available_timestamp, | 
|  | chrome_event_latency.buffer_ready_timestamp, | 
|  | chrome_event_latency.latch_timestamp, | 
|  | chrome_event_latency.presentation_timestamp | 
|  | FROM chrome_scroll_update_refs AS refs | 
|  | LEFT JOIN chrome_event_latencies AS chrome_event_latency | 
|  | ON chrome_event_latency.scroll_update_id = refs.presentation_latency_id | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_input_pipeline_steps AS compositor_resample_step | 
|  | ON compositor_resample_step.latency_id = refs.presentation_latency_id | 
|  | AND compositor_resample_step.step = 'STEP_RESAMPLE_SCROLL_EVENTS' | 
|  | AND compositor_resample_step.input_type = 'GESTURE_SCROLL_UPDATE_EVENT' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_surface_frame_steps AS compositor_receive_begin_frame_step | 
|  | ON compositor_receive_begin_frame_step.surface_frame_trace_id = refs.surface_frame_id | 
|  | AND compositor_receive_begin_frame_step.step = 'STEP_RECEIVE_BEGIN_FRAME' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_surface_frame_steps AS compositor_generate_compositor_frame_step | 
|  | ON compositor_generate_compositor_frame_step.surface_frame_trace_id = refs.surface_frame_id | 
|  | AND compositor_generate_compositor_frame_step.step = 'STEP_GENERATE_COMPOSITOR_FRAME' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_surface_frame_steps AS compositor_submit_compositor_frame_step | 
|  | ON compositor_submit_compositor_frame_step.surface_frame_trace_id = refs.surface_frame_id | 
|  | AND compositor_submit_compositor_frame_step.step = 'STEP_SUBMIT_COMPOSITOR_FRAME' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_surface_frame_steps AS viz_receive_compositor_frame_step | 
|  | ON viz_receive_compositor_frame_step.surface_frame_trace_id = refs.surface_frame_id | 
|  | AND viz_receive_compositor_frame_step.step = 'STEP_RECEIVE_COMPOSITOR_FRAME' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_display_frame_steps AS viz_draw_and_swap_step | 
|  | ON viz_draw_and_swap_step.display_trace_id = refs.display_trace_id | 
|  | AND viz_draw_and_swap_step.step = 'STEP_DRAW_AND_SWAP' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_display_frame_steps AS viz_send_buffer_swap_step | 
|  | ON viz_send_buffer_swap_step.display_trace_id = refs.display_trace_id | 
|  | AND viz_send_buffer_swap_step.step = 'STEP_SEND_BUFFER_SWAP' | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | LEFT JOIN chrome_graphics_pipeline_display_frame_steps AS viz_swap_buffers_step | 
|  | ON viz_swap_buffers_step.display_trace_id = refs.display_trace_id | 
|  | AND viz_swap_buffers_step.step = 'STEP_BUFFER_SWAP_POST_SUBMIT' | 
|  | -- Filter out inputs which were coalesced into a different frame (so that rows | 
|  | -- of this table correspond to frames). | 
|  | WHERE | 
|  | refs.scroll_update_latency_id = refs.presentation_latency_id; | 
|  |  | 
|  | -- Timestamps and durations for the frame-associated (after coalescing inputs | 
|  | -- into a frame) stages of a scroll. | 
|  | CREATE PERFETTO TABLE chrome_scroll_update_frame_pipeline ( | 
|  | -- Id of the `LatencyInfo.Flow` slices corresponding to this scroll event. | 
|  | id LONG, | 
|  | -- Id of the aggregated frame this scroll update was presented in. | 
|  | display_trace_id LONG, | 
|  | -- Vsync interval (in milliseconds). | 
|  | vsync_interval_ms DOUBLE, | 
|  | -- Slice id for the `STEP_RESAMPLE_SCROLL_EVENTS` slice. | 
|  | compositor_resample_slice_id LONG, | 
|  | -- Timestamp for the `STEP_RESAMPLE_SCROLL_EVENTS` slice. | 
|  | compositor_resample_ts TIMESTAMP, | 
|  | -- Timestamp for the `STEP_RECEIVE_BEGIN_FRAME` slice or the | 
|  | -- containing task (if available). | 
|  | compositor_receive_begin_frame_ts TIMESTAMP, | 
|  | -- Slice id for the `STEP_GENERATE_COMPOSITOR_FRAME` slice. | 
|  | compositor_generate_compositor_frame_slice_id LONG, | 
|  | -- Timestamp for the `STEP_GENERATE_COMPOSITOR_FRAME` slice or the | 
|  | -- containing task (if available). | 
|  | compositor_generate_compositor_frame_ts TIMESTAMP, | 
|  | -- Duration between generating and submitting the compositor frame. | 
|  | compositor_generate_frame_to_submit_frame_dur DURATION, | 
|  | -- Slice id for the `STEP_SUBMIT_COMPOSITOR_FRAME` slice. | 
|  | compositor_submit_compositor_frame_slice_id LONG, | 
|  | -- Timestamp for the `STEP_SUBMIT_COMPOSITOR_FRAME` slice. | 
|  | compositor_submit_compositor_frame_ts TIMESTAMP, | 
|  | -- Duration for submitting the compositor frame (to viz). | 
|  | compositor_submit_frame_dur DURATION, | 
|  | -- End timestamp for the `STEP_SUBMIT_COMPOSITOR_FRAME` slice. | 
|  | compositor_submit_compositor_frame_end_ts TIMESTAMP, | 
|  | -- Delay when a compositor frame is sent from the renderer to viz. | 
|  | compositor_to_viz_delay_dur DURATION, | 
|  | -- Utid for the viz compositor thread. | 
|  | viz_compositor_utid LONG, | 
|  | -- Slice id for the `STEP_RECEIVE_COMPOSITOR_FRAME` slice. | 
|  | viz_receive_compositor_frame_slice_id LONG, | 
|  | -- Timestamp for the `STEP_RECEIVE_COMPOSITOR_FRAME` slice or the | 
|  | -- containing task (if available). | 
|  | viz_receive_compositor_frame_ts TIMESTAMP, | 
|  | -- Duration of the viz work done on receiving the compositor frame. | 
|  | viz_receive_compositor_frame_dur DURATION, | 
|  | -- End timestamp for the `STEP_RECEIVE_COMPOSITOR_FRAME` slice. | 
|  | viz_receive_compositor_frame_end_ts TIMESTAMP, | 
|  | -- Duration between viz receiving the compositor frame to frame draw. | 
|  | viz_wait_for_draw_dur DURATION, | 
|  | -- Slice id for the `STEP_DRAW_AND_SWAP` slice. | 
|  | viz_draw_and_swap_slice_id LONG, | 
|  | -- Timestamp for the `STEP_DRAW_AND_SWAP` slice or the | 
|  | -- containing task (if available). | 
|  | viz_draw_and_swap_ts TIMESTAMP, | 
|  | -- Duration for the viz drawing/swapping work for this frame. | 
|  | viz_draw_and_swap_dur DURATION, | 
|  | -- Slice id for the `STEP_SEND_BUFFER_SWAP` slice. | 
|  | viz_send_buffer_swap_slice_id LONG, | 
|  | -- End timestamp for the `STEP_SEND_BUFFER_SWAP` slice. | 
|  | viz_send_buffer_swap_end_ts TIMESTAMP, | 
|  | -- Delay between viz work on compositor thread and `CompositorGpuThread`. | 
|  | viz_to_gpu_delay_dur DURATION, | 
|  | -- Utid for the viz `CompositorGpuThread`. | 
|  | viz_gpu_thread_utid LONG, | 
|  | -- Slice id for the `STEP_BUFFER_SWAP_POST_SUBMIT` slice. | 
|  | viz_swap_buffers_slice_id LONG, | 
|  | -- Timestamp for the `STEP_BUFFER_SWAP_POST_SUBMIT` slice or the | 
|  | -- containing task (if available). | 
|  | viz_swap_buffers_ts TIMESTAMP, | 
|  | -- Duration of frame buffer swapping work on viz. | 
|  | viz_swap_buffers_dur DURATION, | 
|  | -- End timestamp for the `STEP_BUFFER_SWAP_POST_SUBMIT` slice. | 
|  | viz_swap_buffers_end_ts TIMESTAMP, | 
|  | -- Duration of `EventLatency`'s `BufferReadyToLatch` step. | 
|  | viz_swap_buffers_to_latch_dur DURATION, | 
|  | -- Timestamp for `EventLatency`'s `LatchToSwapEnd` step. | 
|  | latch_timestamp TIMESTAMP, | 
|  | -- Duration of either `EventLatency`'s `LatchToSwapEnd` + | 
|  | -- `SwapEndToPresentationCompositorFrame` steps or its `LatchToPresentation` | 
|  | -- step. | 
|  | viz_latch_to_presentation_dur DURATION, | 
|  | -- Presentation timestamp for the frame. | 
|  | presentation_timestamp TIMESTAMP | 
|  | ) AS | 
|  | WITH | 
|  | processed_timestamps_and_metadata AS ( | 
|  | SELECT | 
|  | id, | 
|  | display_trace_id, | 
|  | vsync_interval_ms, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | compositor_resample_slice_id, | 
|  | -- Timestamps | 
|  | coalesce(compositor_resample_task_ts, compositor_resample_ts) AS compositor_resample_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | compositor_receive_begin_frame_slice_id, | 
|  | -- Timestamps | 
|  | coalesce(compositor_receive_begin_frame_task_ts, compositor_receive_begin_frame_ts) AS compositor_receive_begin_frame_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | compositor_generate_compositor_frame_slice_id, | 
|  | -- Timestamps | 
|  | coalesce( | 
|  | compositor_generate_compositor_frame_task_ts, | 
|  | compositor_generate_compositor_frame_ts | 
|  | ) AS compositor_generate_compositor_frame_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | compositor_submit_compositor_frame_slice_id, | 
|  | -- Timestamps | 
|  | compositor_submit_compositor_frame_ts, | 
|  | compositor_submit_compositor_frame_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | viz_compositor_utid, | 
|  | viz_receive_compositor_frame_slice_id, | 
|  | -- Timestamps | 
|  | coalesce(viz_receive_compositor_frame_task_ts, viz_receive_compositor_frame_ts) AS viz_receive_compositor_frame_ts, | 
|  | viz_receive_compositor_frame_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | viz_draw_and_swap_slice_id, | 
|  | -- Timestamps | 
|  | coalesce(viz_draw_and_swap_task_ts, viz_draw_and_swap_ts) AS viz_draw_and_swap_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | viz_send_buffer_swap_slice_id, | 
|  | -- Timestamps | 
|  | viz_send_buffer_swap_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Ids | 
|  | viz_gpu_thread_utid, | 
|  | viz_swap_buffers_slice_id, | 
|  | -- Timestamps | 
|  | coalesce(viz_swap_buffers_task_ts, viz_swap_buffers_ts) AS viz_swap_buffers_ts, | 
|  | viz_swap_buffers_end_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- Timestamps | 
|  | latch_timestamp, | 
|  | presentation_timestamp | 
|  | FROM _scroll_update_frame_timestamps_and_metadata | 
|  | ) | 
|  | SELECT | 
|  | id, | 
|  | display_trace_id, | 
|  | -- TODO(b:381062412): This is sometimes unexpectedly 0; check/fix this. | 
|  | vsync_interval_ms, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | compositor_resample_slice_id, | 
|  | compositor_resample_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | compositor_receive_begin_frame_ts, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | compositor_generate_compositor_frame_slice_id, | 
|  | -- TODO(b:380868337): This is sometimes unexpectedly null; check/fix this. | 
|  | compositor_generate_compositor_frame_ts, | 
|  | compositor_submit_compositor_frame_ts - compositor_generate_compositor_frame_ts AS compositor_generate_frame_to_submit_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | compositor_submit_compositor_frame_slice_id, | 
|  | compositor_submit_compositor_frame_ts, | 
|  | compositor_submit_compositor_frame_end_ts - compositor_submit_compositor_frame_ts AS compositor_submit_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | -- No applicable slice id (duration between two threads). | 
|  | compositor_submit_compositor_frame_end_ts, | 
|  | -- TODO(b:380868337): This is sometimes negative; check/fix this. | 
|  | viz_receive_compositor_frame_ts - compositor_submit_compositor_frame_end_ts AS compositor_to_viz_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_compositor_utid, | 
|  | viz_receive_compositor_frame_slice_id, | 
|  | viz_receive_compositor_frame_ts, | 
|  | viz_receive_compositor_frame_end_ts - viz_receive_compositor_frame_ts AS viz_receive_compositor_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `viz_compositor_utid`. | 
|  | -- No applicable slice id (duration between two slices). | 
|  | viz_receive_compositor_frame_end_ts, | 
|  | viz_draw_and_swap_ts - viz_receive_compositor_frame_end_ts AS viz_wait_for_draw_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `viz_compositor_utid`. | 
|  | viz_draw_and_swap_slice_id, | 
|  | viz_draw_and_swap_ts, | 
|  | viz_send_buffer_swap_end_ts - viz_draw_and_swap_ts AS viz_draw_and_swap_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | viz_send_buffer_swap_slice_id, | 
|  | viz_send_buffer_swap_end_ts, | 
|  | viz_swap_buffers_ts - viz_send_buffer_swap_end_ts AS viz_to_gpu_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_gpu_thread_utid, | 
|  | viz_swap_buffers_slice_id, | 
|  | viz_swap_buffers_ts, | 
|  | viz_swap_buffers_end_ts - viz_swap_buffers_ts AS viz_swap_buffers_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | viz_swap_buffers_end_ts, | 
|  | latch_timestamp - viz_swap_buffers_end_ts AS viz_swap_buffers_to_latch_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | latch_timestamp, | 
|  | presentation_timestamp - latch_timestamp AS viz_latch_to_presentation_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | presentation_timestamp | 
|  | FROM processed_timestamps_and_metadata; | 
|  |  | 
|  | -- Defines slices for all of the individual scrolls in a trace based on the | 
|  | -- LatencyInfo-based scroll definition. | 
|  | -- | 
|  | -- NOTE: this view of top level scrolls is based on the LatencyInfo definition | 
|  | -- of a scroll, which differs subtly from the definition based on | 
|  | -- EventLatencies. | 
|  | -- TODO(b/278684408): add support for tracking scrolls across multiple Chrome/ | 
|  | -- WebView instances. Currently gesture_scroll_id unique within an instance, but | 
|  | -- is not unique across multiple instances. Switching to an EventLatency based | 
|  | -- definition of scrolls should resolve this. | 
|  | CREATE PERFETTO TABLE chrome_scrolls ( | 
|  | -- The unique identifier of the scroll. | 
|  | id LONG, | 
|  | -- The start timestamp of the scroll. | 
|  | ts TIMESTAMP, | 
|  | -- The duration of the scroll. | 
|  | dur DURATION, | 
|  | -- The earliest timestamp of the EventLatency slice of the GESTURE_SCROLL_BEGIN type for the | 
|  | -- corresponding scroll id. | 
|  | gesture_scroll_begin_ts TIMESTAMP, | 
|  | -- The earliest timestamp of the EventLatency slice of the GESTURE_SCROLL_END type / | 
|  | -- the latest timestamp of the EventLatency slice of the GESTURE_SCROLL_UPDATE type for the | 
|  | -- corresponding scroll id. | 
|  | gesture_scroll_end_ts TIMESTAMP | 
|  | ) AS | 
|  | SELECT | 
|  | scroll_id AS id, | 
|  | min(ts) AS ts, | 
|  | cast_int!(MAX(ts + dur) - MIN(ts)) AS dur, | 
|  | -- TODO(b:389055670): Remove this once the UI doesn't rely on it. | 
|  | NULL AS gesture_scroll_begin_ts, | 
|  | NULL AS gesture_scroll_end_ts | 
|  | FROM chrome_gesture_scroll_updates | 
|  | GROUP BY | 
|  | scroll_id; | 
|  |  | 
|  | -- Timestamps and durations for the critical path stages during scrolling. | 
|  | -- This table covers both the input-associated (before coalescing inputs into a | 
|  | -- frame) and frame-associated (after coalescing inputs into a frame) stages of | 
|  | -- a scroll: | 
|  | -- | 
|  | --                              ... | 
|  | --                               | | 
|  | --                +--------------+--------------+ | 
|  | --                |                             | | 
|  | --                V                             V | 
|  | --   +-------------------------+   +-------------------------+ | 
|  | --   | _scroll_update_INPUT_   |   | _scroll_update_FRAME_   | | 
|  | --   | timestamps_and_metadata |   | timestamps_and_metadata | | 
|  | --   +------------+------------+   +------------+------------+ | 
|  | --                |                             | | 
|  | --                V                             V | 
|  | --    +-----------------------+     +-----------------------+ | 
|  | --    | chrome_scroll_update_ |     | chrome_scroll_update_ | | 
|  | --    |     INPUT_pipeline    |     |     FRAME_pipeline    | | 
|  | --    +-----------+-----------+     +-----------+-----------+ | 
|  | --                |                             | | 
|  | --                +--------------+--------------+ | 
|  | --                               | | 
|  | --                               V | 
|  | --                 +---------------------------+ | 
|  | --                 | chrome_scroll_update_info | | 
|  | --                 +---------------------------+ | 
|  | CREATE PERFETTO TABLE chrome_scroll_update_info ( | 
|  | -- Id of the `LatencyInfo.Flow` slices corresponding to this scroll event. | 
|  | id LONG, | 
|  | -- Id of the scroll this scroll update belongs to. | 
|  | scroll_id LONG, | 
|  | -- Id (`LatencyInfo.ID`) of the previous input in this scroll. | 
|  | previous_input_id LONG, | 
|  | -- Id (`display_trace_id`) of the aggregated frame which this scroll update | 
|  | -- was presented in. | 
|  | frame_display_id LONG, | 
|  | -- Vsync interval (in milliseconds). | 
|  | vsync_interval_ms DOUBLE, | 
|  | -- Whether this input event was presented. | 
|  | is_presented BOOL, | 
|  | -- Whether the corresponding frame is janky based on the | 
|  | -- Event.ScrollJank.DelayedFramesPercentage.FixedWindow metric. This comes | 
|  | -- directly from `perfetto.protos.EventLatency.is_janky_scrolled_frame`. | 
|  | is_janky BOOL, | 
|  | -- Whether the corresponding frame is janky based on the | 
|  | -- Event.ScrollJank.DelayedFramesPercentage.FixedWindow3 metric. This comes | 
|  | -- directly from `perfetto.protos.EventLatency.is_janky_scrolled_frame_v3`. | 
|  | is_janky_v3 BOOL, | 
|  | -- Whether the corresponding scroll is inertial (fling). | 
|  | -- If this is `true`, "generation" and "touch_move" related timestamps and | 
|  | -- durations will be null. | 
|  | is_inertial BOOL, | 
|  | -- Whether this is the first update in a scroll. | 
|  | -- First scroll update can never be janky. | 
|  | is_first_scroll_update_in_scroll BOOL, | 
|  | -- Whether this is the first input that was presented in the frame. | 
|  | is_first_scroll_update_in_frame BOOL, | 
|  | -- Duration from the start of the browser process to the first | 
|  | -- input generation timestamp. | 
|  | browser_uptime_dur DURATION, | 
|  | -- Input generation timestamp (from the Android system). | 
|  | generation_ts TIMESTAMP, | 
|  | -- Duration from the generation timestamp to the end of InputReader's work. | 
|  | -- Only populated when atrace 'input' category is enabled. | 
|  | input_reader_dur DURATION, | 
|  | -- Duration of InputDispatcher's work. | 
|  | -- Only populated when atrace 'input' category is enabled. | 
|  | input_dispatcher_dur DURATION, | 
|  | -- Duration from the generation timestamp for the previous input to | 
|  | -- this input's generation timestamp. | 
|  | since_previous_generation_dur DURATION, | 
|  | -- Duration from input generation to when the browser received the input. | 
|  | generation_to_browser_main_dur DURATION, | 
|  | -- Utid for the browser main thread. | 
|  | browser_utid LONG, | 
|  | -- Slice id for the `STEP_SEND_INPUT_EVENT_UI` slice for the touch move. | 
|  | touch_move_received_slice_id LONG, | 
|  | -- Timestamp for the `STEP_SEND_INPUT_EVENT_UI` slice for the touch move. | 
|  | touch_move_received_ts TIMESTAMP, | 
|  | -- Duration for processing  a `TouchMove` event. | 
|  | touch_move_processing_dur DURATION, | 
|  | -- Slice id for the `STEP_SEND_INPUT_EVENT_UI` slice for the gesture scroll. | 
|  | scroll_update_created_slice_id LONG, | 
|  | -- Timestamp for the `STEP_SEND_INPUT_EVENT_UI` slice for the gesture scroll. | 
|  | scroll_update_created_ts TIMESTAMP, | 
|  | -- Duration for creating a `GestureScrollUpdate` from a `TouchMove` event. | 
|  | scroll_update_processing_dur DURATION, | 
|  | -- End timestamp for the `STEP_SEND_INPUT_EVENT_UI` slice for the above. | 
|  | scroll_update_created_end_ts TIMESTAMP, | 
|  | -- Duration between the browser and compositor dispatch. | 
|  | browser_to_compositor_delay_dur DURATION, | 
|  | -- Utid for the renderer compositor thread. | 
|  | compositor_utid LONG, | 
|  | -- Slice id for the `STEP_HANDLE_INPUT_EVENT_IMPL` slice. | 
|  | compositor_dispatch_slice_id LONG, | 
|  | -- Timestamp for the `STEP_HANDLE_INPUT_EVENT_IMPL` slice or the | 
|  | -- containing task (if available). | 
|  | compositor_dispatch_ts TIMESTAMP, | 
|  | -- Duration for the compositor dispatch itself. | 
|  | compositor_dispatch_dur DURATION, | 
|  | -- End timestamp for the `STEP_HANDLE_INPUT_EVENT_IMPL` slice. | 
|  | compositor_dispatch_end_ts TIMESTAMP, | 
|  | -- Duration between compositor dispatch and input resampling work. | 
|  | compositor_dispatch_to_on_begin_frame_delay_dur DURATION, | 
|  | -- Slice id for the `STEP_RESAMPLE_SCROLL_EVENTS` slice. | 
|  | compositor_resample_slice_id LONG, | 
|  | -- Slice id for the `STEP_DID_HANDLE_INPUT_AND_OVERSCROLL` slice. | 
|  | compositor_coalesced_input_handled_slice_id LONG, | 
|  | -- Start timestamp for work done on the input during "OnBeginFrame". | 
|  | compositor_on_begin_frame_ts TIMESTAMP, | 
|  | -- Duration of the "OnBeginFrame" work for this input. | 
|  | compositor_on_begin_frame_dur DURATION, | 
|  | -- End timestamp for work done on the input during "OnBeginFrame". | 
|  | compositor_on_begin_frame_end_ts TIMESTAMP, | 
|  | -- Delay until the compositor work for generating the frame begins. | 
|  | compositor_on_begin_frame_to_generation_delay_dur DURATION, | 
|  | -- Slice id for the `STEP_GENERATE_COMPOSITOR_FRAME` slice. | 
|  | compositor_generate_compositor_frame_slice_id LONG, | 
|  | -- Timestamp for the `STEP_GENERATE_COMPOSITOR_FRAME` slice or the | 
|  | -- containing task (if available). | 
|  | compositor_generate_compositor_frame_ts TIMESTAMP, | 
|  | -- Duration between generating and submitting the compositor frame. | 
|  | compositor_generate_frame_to_submit_frame_dur DURATION, | 
|  | -- Slice id for the `STEP_SUBMIT_COMPOSITOR_FRAME` slice. | 
|  | compositor_submit_compositor_frame_slice_id LONG, | 
|  | -- Timestamp for the `STEP_SUBMIT_COMPOSITOR_FRAME` slice. | 
|  | compositor_submit_compositor_frame_ts TIMESTAMP, | 
|  | -- Duration for submitting the compositor frame (to viz). | 
|  | compositor_submit_frame_dur DURATION, | 
|  | -- End timestamp for the `STEP_SUBMIT_COMPOSITOR_FRAME` slice. | 
|  | compositor_submit_compositor_frame_end_ts TIMESTAMP, | 
|  | -- Delay when a compositor frame is sent from the renderer to viz. | 
|  | compositor_to_viz_delay_dur DURATION, | 
|  | -- Utid for the viz compositor thread. | 
|  | viz_compositor_utid LONG, | 
|  | -- Slice id for the `STEP_RECEIVE_COMPOSITOR_FRAME` slice. | 
|  | viz_receive_compositor_frame_slice_id LONG, | 
|  | -- Timestamp for the `STEP_RECEIVE_COMPOSITOR_FRAME` slice or the | 
|  | -- containing task (if available). | 
|  | viz_receive_compositor_frame_ts TIMESTAMP, | 
|  | -- Duration of the viz work done on receiving the compositor frame. | 
|  | viz_receive_compositor_frame_dur DURATION, | 
|  | -- End timestamp for the `STEP_RECEIVE_COMPOSITOR_FRAME` slice. | 
|  | viz_receive_compositor_frame_end_ts TIMESTAMP, | 
|  | -- Duration between viz receiving the compositor frame to frame draw. | 
|  | viz_wait_for_draw_dur DURATION, | 
|  | -- Slice id for the `STEP_DRAW_AND_SWAP` slice. | 
|  | viz_draw_and_swap_slice_id LONG, | 
|  | -- Timestamp for the `STEP_DRAW_AND_SWAP` slice or the | 
|  | -- containing task (if available). | 
|  | viz_draw_and_swap_ts TIMESTAMP, | 
|  | -- Duration for the viz drawing/swapping work for this frame. | 
|  | viz_draw_and_swap_dur DURATION, | 
|  | -- Slice id for the `STEP_SEND_BUFFER_SWAP` slice. | 
|  | viz_send_buffer_swap_slice_id LONG, | 
|  | -- End timestamp for the `STEP_SEND_BUFFER_SWAP` slice. | 
|  | viz_send_buffer_swap_end_ts TIMESTAMP, | 
|  | -- Delay between viz work on compositor thread and `CompositorGpuThread`. | 
|  | viz_to_gpu_delay_dur DURATION, | 
|  | -- Utid for the viz `CompositorGpuThread`. | 
|  | viz_gpu_thread_utid LONG, | 
|  | -- Slice id for the `STEP_BUFFER_SWAP_POST_SUBMIT` slice. | 
|  | viz_swap_buffers_slice_id LONG, | 
|  | -- Timestamp for the `STEP_BUFFER_SWAP_POST_SUBMIT` slice or the | 
|  | -- containing task (if available). | 
|  | viz_swap_buffers_ts TIMESTAMP, | 
|  | -- Duration of frame buffer swapping work on viz. | 
|  | viz_swap_buffers_dur DURATION, | 
|  | -- End timestamp for the `STEP_BUFFER_SWAP_POST_SUBMIT` slice. | 
|  | viz_swap_buffers_end_ts TIMESTAMP, | 
|  | -- Duration of `EventLatency`'s `BufferReadyToLatch` step. | 
|  | viz_swap_buffers_to_latch_dur DURATION, | 
|  | -- Timestamp for `EventLatency`'s `LatchToSwapEnd` step. | 
|  | latch_timestamp TIMESTAMP, | 
|  | -- Duration of either `EventLatency`'s `LatchToSwapEnd` + | 
|  | -- `SwapEndToPresentationCompositorFrame` steps or its `LatchToPresentation` | 
|  | -- step. | 
|  | viz_latch_to_presentation_dur DURATION, | 
|  | -- Presentation timestamp for the frame. | 
|  | presentation_timestamp TIMESTAMP | 
|  | ) AS | 
|  | SELECT | 
|  | input.id, | 
|  | input.scroll_id, | 
|  | lag(input.id) OVER (PARTITION BY input.scroll_id ORDER BY input.generation_ts) AS previous_input_id, | 
|  | frame.display_trace_id AS frame_display_id, | 
|  | -- TODO(b:381062412): This is sometimes unexpectedly 0; check/fix this. | 
|  | frame.vsync_interval_ms, | 
|  | input.is_presented, | 
|  | input.is_janky, | 
|  | input.is_janky_v3, | 
|  | input.is_inertial, | 
|  | input.is_first_scroll_update_in_scroll, | 
|  | input.is_first_scroll_update_in_frame, | 
|  | generation_ts - browser_process.start_ts AS browser_uptime_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | -- No applicable slice id (duration between two threads). | 
|  | input.generation_ts, | 
|  | input.input_reader_processing_end_ts - generation_ts AS input_reader_dur, | 
|  | input.input_dispatcher_processing_end_ts - input.input_reader_processing_end_ts AS input_dispatcher_dur, | 
|  | input.generation_ts - lag(input.generation_ts) OVER (PARTITION BY input.scroll_id ORDER BY input.generation_ts) AS since_previous_generation_dur, | 
|  | input.generation_to_browser_main_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | input.browser_utid, | 
|  | input.touch_move_received_slice_id, | 
|  | input.touch_move_received_ts, | 
|  | input.touch_move_processing_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `browser_utid`. | 
|  | input.scroll_update_created_slice_id, | 
|  | input.scroll_update_created_ts, | 
|  | input.scroll_update_processing_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | -- No applicable slice id (duration between two threads). | 
|  | input.scroll_update_created_end_ts, | 
|  | -- TODO(b:380868337): This is sometimes negative; check/fix this. | 
|  | input.browser_to_compositor_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | input.compositor_utid, | 
|  | input.compositor_dispatch_slice_id, | 
|  | input.compositor_dispatch_ts, | 
|  | input.compositor_dispatch_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | -- No applicable slice id (duration between two slices). | 
|  | input.compositor_dispatch_end_ts, | 
|  | -- TODO(b:380868337): This is sometimes negative; check/fix this. | 
|  | -- TODO(b:381273884): use frame.compositor_receive_begin_frame_ts instead of | 
|  | -- input.compositor_dispatch_end_ts. | 
|  | coalesce(frame.compositor_resample_ts, input.compositor_coalesced_input_handled_ts) - input.compositor_dispatch_end_ts AS compositor_dispatch_to_on_begin_frame_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | -- `compositor_on_begin_frame_dur` can depend on two slices. | 
|  | frame.compositor_resample_slice_id, | 
|  | input.compositor_coalesced_input_handled_slice_id, | 
|  | coalesce(frame.compositor_resample_ts, input.compositor_coalesced_input_handled_ts) AS compositor_on_begin_frame_ts, | 
|  | input.compositor_coalesced_input_handled_end_ts - coalesce(frame.compositor_resample_ts, input.compositor_coalesced_input_handled_ts) AS compositor_on_begin_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | -- No applicable slice id (duration between two slices). | 
|  | input.compositor_coalesced_input_handled_end_ts AS compositor_on_begin_frame_end_ts, | 
|  | frame.compositor_generate_compositor_frame_ts - input.compositor_coalesced_input_handled_end_ts AS compositor_on_begin_frame_to_generation_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | frame.compositor_generate_compositor_frame_slice_id, | 
|  | -- TODO(b:380868337): This is sometimes unexpectedly null; check/fix this. | 
|  | frame.compositor_generate_compositor_frame_ts, | 
|  | frame.compositor_generate_frame_to_submit_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `compositor_utid`. | 
|  | frame.compositor_submit_compositor_frame_slice_id, | 
|  | frame.compositor_submit_compositor_frame_ts, | 
|  | frame.compositor_submit_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | -- No applicable slice id (duration between two threads). | 
|  | frame.compositor_submit_compositor_frame_end_ts, | 
|  | -- TODO(b:380868337): This is sometimes negative; check/fix this. | 
|  | frame.compositor_to_viz_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | frame.viz_compositor_utid, | 
|  | frame.viz_receive_compositor_frame_slice_id, | 
|  | frame.viz_receive_compositor_frame_ts, | 
|  | frame.viz_receive_compositor_frame_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `viz_compositor_utid`. | 
|  | -- No applicable slice id (duration between two slices). | 
|  | frame.viz_receive_compositor_frame_end_ts, | 
|  | frame.viz_wait_for_draw_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- On `viz_compositor_utid`. | 
|  | frame.viz_draw_and_swap_slice_id, | 
|  | frame.viz_draw_and_swap_ts, | 
|  | frame.viz_draw_and_swap_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | -- No applicable utid (duration between two threads). | 
|  | frame.viz_send_buffer_swap_slice_id, | 
|  | frame.viz_send_buffer_swap_end_ts, | 
|  | frame.viz_to_gpu_delay_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | frame.viz_gpu_thread_utid, | 
|  | frame.viz_swap_buffers_slice_id, | 
|  | frame.viz_swap_buffers_ts, | 
|  | frame.viz_swap_buffers_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | frame.viz_swap_buffers_end_ts, | 
|  | frame.viz_swap_buffers_to_latch_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | frame.latch_timestamp, | 
|  | frame.viz_latch_to_presentation_dur, | 
|  | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 
|  | frame.presentation_timestamp | 
|  | FROM chrome_scroll_update_input_pipeline AS input | 
|  | LEFT JOIN chrome_scroll_update_frame_pipeline AS frame | 
|  | ON input.presented_in_frame_id = frame.id | 
|  | LEFT JOIN thread AS browser_main_thread | 
|  | ON browser_utid = browser_main_thread.utid | 
|  | LEFT JOIN process AS browser_process | 
|  | ON browser_process.upid = browser_main_thread.upid; | 
|  |  | 
|  | -- Helper macro to compute the stage delta. | 
|  | -- Should be used only as a part of `chrome_scroll_frame_info`. | 
|  | CREATE PERFETTO MACRO _chrome_scroll_frame_stage_delta( | 
|  | name ColumnName | 
|  | ) | 
|  | RETURNS Expr AS | 
|  | iif( | 
|  | info.is_first_scroll_update_in_scroll, | 
|  | NULL, | 
|  | $name - lag($name) OVER (ORDER BY generation_ts) | 
|  | ); | 
|  |  | 
|  | -- A list of all presented Chrome frames which contain scroll updates and associated | 
|  | -- metadata. | 
|  | CREATE PERFETTO TABLE chrome_scroll_frame_info ( | 
|  | -- Id (frame's display_trace_id) for the given frame. | 
|  | id LONG, | 
|  | -- Id of the scroll this scroll update belongs to. | 
|  | scroll_id LONG, | 
|  | -- Id (LatencyInfo.ID) of the last input before this frame. | 
|  | last_input_before_this_frame_id LONG, | 
|  | -- Vsync interval (in milliseconds). | 
|  | -- TODO(b/394303662): Remove in favour of `vsync_interval_dur`. | 
|  | vsync_interval_ms DOUBLE, | 
|  | -- Vsync interval (in nanoseconds). | 
|  | vsync_interval_dur DURATION, | 
|  | -- Whether the corresponding frame is janky based on the | 
|  | -- Event.ScrollJank.DelayedFramesPercentage.FixedWindow metric. This comes | 
|  | -- directly from `perfetto.protos.EventLatency.is_janky_scrolled_frame`. | 
|  | is_janky BOOL, | 
|  | -- Whether the corresponding frame is janky based on the | 
|  | -- Event.ScrollJank.DelayedFramesPercentage.FixedWindow3 metric. This comes | 
|  | -- directly from `perfetto.protos.EventLatency.is_janky_scrolled_frame_v3`. | 
|  | is_janky_v3 BOOL, | 
|  | -- Whether the corresponding scroll is inertial (fling). | 
|  | is_inertial BOOL, | 
|  | -- Sum of all input deltas for all scroll updates in this frame. | 
|  | -- These values are based on the delta of the OS input events. | 
|  | total_input_delta_y DOUBLE, | 
|  | -- Presented delta (change in page offset) for the given frame. | 
|  | -- This delta is computed by Chrome (based on the input events). | 
|  | presented_scrolled_delta_y DOUBLE, | 
|  | -- Duration from the start of the browser process to the first | 
|  | -- input generation timestamp. | 
|  | browser_uptime_dur DURATION, | 
|  | -- Input generation timestamp (from the Android system) for the first input. | 
|  | first_input_generation_ts TIMESTAMP, | 
|  | --  Duration from the generation timestamp to the end of InputReader's work. | 
|  | -- Only populated when atrace 'input' category is enabled. | 
|  | input_reader_dur DURATION, | 
|  | -- Duration of InputDispatcher's work. | 
|  | -- Only populated when atrace 'input' category is enabled. | 
|  | input_dispatcher_dur DURATION, | 
|  | -- Duration from the previous input (last input that wasn't part of this frame) | 
|  | -- to the first input in this frame. | 
|  | previous_last_input_to_first_input_generation_dur DURATION, | 
|  | -- Presentation timestamp for the frame. | 
|  | presentation_ts TIMESTAMP, | 
|  | -- Utid for the browser main thread. | 
|  | browser_utid JOINID(thread.id), | 
|  | -- Duration from input generation to when the browser received the first input | 
|  | -- in this frame. | 
|  | first_input_generation_to_browser_main_dur DURATION, | 
|  | -- Difference between `first_input_generation_to_browser_main_dur` for this | 
|  | -- frame and the previous frame in the same scroll. | 
|  | first_input_generation_to_browser_main_delta_dur DURATION, | 
|  | -- Duration for processing  a `TouchMove` event for the first input in this | 
|  | -- frame. | 
|  | first_input_touch_move_processing_dur DURATION, | 
|  | -- Difference between `first_input_touch_move_processing_dur` for this | 
|  | -- frame and the previous frame in the same scroll. | 
|  | first_input_touch_move_processing_delta_dur DURATION, | 
|  | -- Utid for the renderer compositor thread. | 
|  | compositor_utid JOINID(thread.id), | 
|  | -- Duration between the browser and compositor dispatch for the first input | 
|  | -- in this frame. | 
|  | first_input_browser_to_compositor_delay_dur DURATION, | 
|  | -- Difference between `first_input_browser_to_compositor_delay_dur` for this | 
|  | -- frame and the previous frame in the same scroll. | 
|  | first_input_browser_to_compositor_delay_delta_dur DURATION, | 
|  | -- Duration for the compositor dispatch for the first input in this frame. | 
|  | first_input_compositor_dispatch_dur DURATION, | 
|  | -- Difference between `first_input_compositor_dispatch_dur` for this frame and | 
|  | -- the previous frame in the same scroll. | 
|  | first_input_compositor_dispatch_delta_dur DURATION, | 
|  | -- Duration between the compositor dispatch and the "OnBeginFrame" work for the | 
|  | -- first input in this frame. | 
|  | first_input_compositor_dispatch_to_on_begin_frame_delay_dur DURATION, | 
|  | -- Difference between `first_input_compositor_dispatch_to_on_begin_frame_delay_dur` | 
|  | -- for this frame and the previous frame in the same scroll. | 
|  | first_input_compositor_dispatch_to_on_begin_frame_delay_delta_dur DURATION, | 
|  | -- Duration of the "OnBeginFrame" work for this frame. | 
|  | compositor_on_begin_frame_dur DURATION, | 
|  | -- Difference between `compositor_on_begin_frame_dur` for this frame and the | 
|  | -- previous frame in the same scroll. | 
|  | compositor_on_begin_frame_delta_dur DURATION, | 
|  | -- Duration between the "OnBeginFrame" work and the generation of this frame. | 
|  | compositor_on_begin_frame_to_generation_delay_dur DURATION, | 
|  | -- Difference between `compositor_on_begin_frame_to_generation_delay_dur` for | 
|  | -- this frame and the previous frame in the same scroll. | 
|  | compositor_on_begin_frame_to_generation_delay_delta_dur DURATION, | 
|  | -- Duration between the generation and submission of this frame. | 
|  | compositor_generate_frame_to_submit_frame_dur DURATION, | 
|  | -- Difference between `compositor_generate_frame_to_submit_frame_dur` for this | 
|  | -- frame and the previous frame in the same scroll. | 
|  | compositor_generate_frame_to_submit_frame_delta_dur DURATION, | 
|  | -- Duration for submitting this frame. | 
|  | compositor_submit_frame_dur DURATION, | 
|  | -- Difference between `compositor_submit_frame_dur` for this frame and the | 
|  | -- previous frame in the same scroll. | 
|  | compositor_submit_frame_delta_dur DURATION, | 
|  | -- Utid for the viz compositor thread. | 
|  | viz_compositor_utid JOINID(thread.id), | 
|  | -- Delay when a compositor frame is sent from the renderer to viz. | 
|  | compositor_to_viz_delay_dur DURATION, | 
|  | -- Difference between `compositor_to_viz_delay_dur` for this frame and the | 
|  | -- previous frame in the same scroll. | 
|  | compositor_to_viz_delay_delta_dur DURATION, | 
|  | -- Duration of the viz work done on receiving the compositor frame. | 
|  | viz_receive_compositor_frame_dur DURATION, | 
|  | -- Difference between `viz_receive_compositor_frame_dur` for this frame and the | 
|  | -- previous frame in the same scroll. | 
|  | viz_receive_compositor_frame_delta_dur DURATION, | 
|  | -- Duration between viz receiving the compositor frame to frame draw. | 
|  | viz_wait_for_draw_dur DURATION, | 
|  | -- Difference between `viz_wait_for_draw_dur` for this frame and the previous | 
|  | -- frame in the same scroll. | 
|  | viz_wait_for_draw_delta_dur DURATION, | 
|  | -- Duration of the viz drawing/swapping work for this frame. | 
|  | viz_draw_and_swap_dur DURATION, | 
|  | -- Difference between `viz_draw_and_swap_dur` for this frame and the previous | 
|  | -- frame in the same scroll. | 
|  | viz_draw_and_swap_delta_dur DURATION, | 
|  | -- Utid for the viz `CompositorGpuThread`. | 
|  | viz_gpu_thread_utid JOINID(thread.id), | 
|  | -- Delay between viz work on compositor thread and `CompositorGpuThread`. | 
|  | viz_to_gpu_delay_dur DURATION, | 
|  | -- Difference between `viz_to_gpu_delay_dur` for this frame and the previous | 
|  | -- frame in the same scroll. | 
|  | viz_to_gpu_delay_delta_dur DURATION, | 
|  | -- Duration of frame buffer swapping work on viz. | 
|  | viz_swap_buffers_dur DURATION, | 
|  | -- Difference between `viz_swap_buffers_dur` for this frame and the previous | 
|  | -- frame in the same scroll. | 
|  | viz_swap_buffers_delta_dur DURATION, | 
|  | -- Time between buffers ready until Choreographer's latch. | 
|  | viz_swap_buffers_to_latch_dur DURATION, | 
|  | -- Difference between `viz_swap_buffers_to_latch_dur` for this frame and the | 
|  | -- previous frame in the same scroll. | 
|  | viz_swap_buffers_to_latch_delta_dur DURATION, | 
|  | -- Duration between Choreographer's latch and presentation. | 
|  | viz_latch_to_presentation_dur DURATION, | 
|  | -- Difference between `viz_latch_to_presentation_dur` for this frame and the | 
|  | -- previous frame in the same scroll. | 
|  | viz_latch_to_presentation_delta_dur DURATION | 
|  | ) AS | 
|  | SELECT | 
|  | frame_display_id AS id, | 
|  | info.scroll_id, | 
|  | previous_input_id AS last_input_before_this_frame_id, | 
|  | vsync_interval_ms, | 
|  | cast_int!(vsync_interval_ms * 1e6) AS vsync_interval_dur, | 
|  | is_janky, | 
|  | is_janky_v3, | 
|  | is_inertial, | 
|  | ( | 
|  | SELECT | 
|  | sum(delta_y) | 
|  | FROM chrome_scroll_input_offsets AS input | 
|  | JOIN chrome_scroll_update_info AS update_info | 
|  | ON input.scroll_update_id = update_info.id | 
|  | WHERE | 
|  | update_info.frame_display_id = info.frame_display_id | 
|  | ) AS total_input_delta_y, | 
|  | delta.delta_y AS presented_scrolled_delta_y, | 
|  | browser_uptime_dur, | 
|  | info.generation_ts AS first_input_generation_ts, | 
|  | input_reader_dur, | 
|  | input_dispatcher_dur, | 
|  | info.since_previous_generation_dur AS previous_last_input_to_first_input_generation_dur, | 
|  | info.browser_utid, | 
|  | info.generation_to_browser_main_dur AS first_input_generation_to_browser_main_dur, | 
|  | presentation_timestamp AS presentation_ts, | 
|  | _chrome_scroll_frame_stage_delta!(generation_to_browser_main_dur) AS first_input_generation_to_browser_main_delta_dur, | 
|  | info.touch_move_processing_dur AS first_input_touch_move_processing_dur, | 
|  | _chrome_scroll_frame_stage_delta!(touch_move_processing_dur) AS first_input_touch_move_processing_delta_dur, | 
|  | info.compositor_utid, | 
|  | info.browser_to_compositor_delay_dur AS first_input_browser_to_compositor_delay_dur, | 
|  | _chrome_scroll_frame_stage_delta!(browser_to_compositor_delay_dur) AS first_input_browser_to_compositor_delay_delta_dur, | 
|  | info.compositor_dispatch_dur AS first_input_compositor_dispatch_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_dispatch_dur) AS first_input_compositor_dispatch_delta_dur, | 
|  | info.compositor_dispatch_to_on_begin_frame_delay_dur AS first_input_compositor_dispatch_to_on_begin_frame_delay_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_dispatch_to_on_begin_frame_delay_dur) AS first_input_compositor_dispatch_to_on_begin_frame_delay_delta_dur, | 
|  | info.compositor_on_begin_frame_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_on_begin_frame_dur) AS compositor_on_begin_frame_delta_dur, | 
|  | info.compositor_on_begin_frame_to_generation_delay_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_on_begin_frame_to_generation_delay_dur) AS compositor_on_begin_frame_to_generation_delay_delta_dur, | 
|  | info.compositor_generate_frame_to_submit_frame_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_generate_frame_to_submit_frame_dur) AS compositor_generate_frame_to_submit_frame_delta_dur, | 
|  | info.compositor_submit_frame_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_submit_frame_dur) AS compositor_submit_frame_delta_dur, | 
|  | viz_compositor_utid, | 
|  | info.compositor_to_viz_delay_dur, | 
|  | _chrome_scroll_frame_stage_delta!(compositor_to_viz_delay_dur) AS compositor_to_viz_delay_delta_dur, | 
|  | info.viz_receive_compositor_frame_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_receive_compositor_frame_dur) AS viz_receive_compositor_frame_delta_dur, | 
|  | info.viz_wait_for_draw_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_wait_for_draw_dur) AS viz_wait_for_draw_delta_dur, | 
|  | info.viz_draw_and_swap_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_draw_and_swap_dur) AS viz_draw_and_swap_delta_dur, | 
|  | viz_gpu_thread_utid, | 
|  | info.viz_to_gpu_delay_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_to_gpu_delay_dur) AS viz_to_gpu_delay_delta_dur, | 
|  | info.viz_swap_buffers_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_swap_buffers_dur) AS viz_swap_buffers_delta_dur, | 
|  | info.viz_swap_buffers_to_latch_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_swap_buffers_to_latch_dur) AS viz_swap_buffers_to_latch_delta_dur, | 
|  | info.viz_latch_to_presentation_dur, | 
|  | _chrome_scroll_frame_stage_delta!(viz_latch_to_presentation_dur) AS viz_latch_to_presentation_delta_dur | 
|  | FROM chrome_scroll_update_info AS info | 
|  | LEFT JOIN chrome_presented_scroll_offsets AS delta | 
|  | ON info.id = delta.scroll_update_id | 
|  | -- TODO(b:380286381, b:393051057): remove the frame_display_id condition when dropped frames are handled. | 
|  | WHERE | 
|  | is_first_scroll_update_in_frame AND info.frame_display_id IS NOT NULL; | 
|  |  | 
|  | -- Source of truth for the definition of the stages of a scroll. Mainly intended | 
|  | -- for visualization purposes (e.g. in Chrome Scroll Jank plugin). | 
|  | CREATE PERFETTO TABLE chrome_scroll_update_info_step_templates ( | 
|  | -- The name of a stage of a scroll. | 
|  | step_name STRING, | 
|  | -- The name of the column in `chrome_scroll_update_info` which contains the | 
|  | -- timestamp of the stage. | 
|  | ts_column_name STRING, | 
|  | -- The name of the column in `chrome_scroll_update_info` which contains the | 
|  | -- duration of the stage. NULL if the stage doesn't have a duration. | 
|  | dur_column_name STRING | 
|  | ) AS | 
|  | WITH | 
|  | steps(step_name, ts_column_name, dur_column_name) AS ( | 
|  | SELECT | 
|  | * | 
|  | FROM (VALUES | 
|  | ('GenerationToBrowserMain', 'generation_ts', 'generation_to_browser_main_dur'), | 
|  | ('TouchMoveProcessing', 'touch_move_received_ts', 'touch_move_processing_dur'), | 
|  | ( | 
|  | 'ScrollUpdateProcessing', | 
|  | 'scroll_update_created_ts', | 
|  | 'scroll_update_processing_dur' | 
|  | ), | 
|  | ( | 
|  | 'BrowserMainToRendererCompositor', | 
|  | 'scroll_update_created_end_ts', | 
|  | 'browser_to_compositor_delay_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorDispatch', | 
|  | 'compositor_dispatch_ts', | 
|  | 'compositor_dispatch_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorDispatchToOnBeginFrame', | 
|  | 'compositor_dispatch_end_ts', | 
|  | 'compositor_dispatch_to_on_begin_frame_delay_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorBeginFrame', | 
|  | 'compositor_on_begin_frame_ts', | 
|  | 'compositor_on_begin_frame_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorBeginToGenerateFrame', | 
|  | 'compositor_on_begin_frame_end_ts', | 
|  | 'compositor_on_begin_frame_to_generation_delay_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorGenerateToSubmitFrame', | 
|  | 'compositor_generate_compositor_frame_ts', | 
|  | 'compositor_generate_frame_to_submit_frame_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorSubmitFrame', | 
|  | 'compositor_submit_compositor_frame_ts', | 
|  | 'compositor_submit_frame_dur' | 
|  | ), | 
|  | ( | 
|  | 'RendererCompositorToViz', | 
|  | 'compositor_submit_compositor_frame_end_ts', | 
|  | 'compositor_to_viz_delay_dur' | 
|  | ), | 
|  | ( | 
|  | 'VizReceiveFrame', | 
|  | 'viz_receive_compositor_frame_ts', | 
|  | 'viz_receive_compositor_frame_dur' | 
|  | ), | 
|  | ( | 
|  | 'VizReceiveToDrawFrame', | 
|  | 'viz_receive_compositor_frame_end_ts', | 
|  | 'viz_wait_for_draw_dur' | 
|  | ), | 
|  | ('VizDrawToSwapFrame', 'viz_draw_and_swap_ts', 'viz_draw_and_swap_dur'), | 
|  | ('VizToGpu', 'viz_send_buffer_swap_end_ts', 'viz_to_gpu_delay_dur'), | 
|  | ('VizSwapBuffers', 'viz_swap_buffers_ts', 'viz_swap_buffers_dur'), | 
|  | ( | 
|  | 'VizSwapBuffersToLatch', | 
|  | 'viz_swap_buffers_end_ts', | 
|  | 'viz_swap_buffers_to_latch_dur' | 
|  | ), | 
|  | ('VizLatchToPresentation', 'latch_timestamp', 'viz_latch_to_presentation_dur'), | 
|  | ('Presentation', 'presentation_timestamp', NULL)) AS _values | 
|  | ) | 
|  | SELECT | 
|  | step_name, | 
|  | ts_column_name, | 
|  | dur_column_name | 
|  | FROM steps; |