blob: 0b50e4ab8402c627157172d1073dc0ec30eb0814 [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.
-- Matches slices with frames within CUJs and aggregates slices durations within each frame.
-- This allows comparing the cumulative durations of a set of slices vs what was the expected
-- duration of each frame. It can be a useful heuristic to figure out what contributed to
-- frames missing their expected deadlines.
--
-- EXAMPLE:
--
--
-- CUJ Frames:
--
-- |==== FRAME 1 ====|
-- |====== FRAME 2 ======|
-- |== FRAME 3 ==|
-- |== FRAME 4 ==|
--
-- Main thread frame boundaries:
--
-- |= FRAME 1 =|==== FRAME 2 ====| |= FRAME 3 =||= FRAME 4 =|
--
-- `relevant_slice_table_name` slices:
--
-- |== binder ==| |== binder ==| |=b=| |=b=||=b=|
--
--
-- OUTPUT:
--
-- Data in `*_slice_in_frame` - slices from `relevant_slice_table_name` matched
-- to frames and trimmed to their boundaries:
--
-- * FRAME 1:
-- | binder |
-- * FRAME 2:
-- |== binder ==|
-- * FRAME 3:
-- |=b=||=b=|
-- * FRAME 4 - not present in the output
--
--
-- Data in `*_slice_in_frame_agg` is just an aggregation of durations in *_slice_in_frame.
-- For simplicity we allow `relevant_slice_table_name` to be based on any
-- of the slice tables. This table filters it down to only include slices within
-- the (broadly bounded) CUJ and on the specific process / thread.
-- Using TABLE and not VIEW as this gives better, localized error messages in cases
-- `relevant_slice_table_name` is not correct (e.g. missing cuj_id).
DROP TABLE IF EXISTS {{table_name_prefix}}_query_slice;
CREATE TABLE {{table_name_prefix}}_query_slice AS
SELECT
slice.cuj_id,
slice.utid,
slice.id,
slice.name,
slice.ts,
slice.dur,
slice.ts_end
FROM {{relevant_slice_table_name}} slice
JOIN {{slice_table_name}} android_jank_cuj_slice_table
USING (cuj_id, id);
-- Flat view of frames and slices matched and "trimmed" to each frame boundaries.
DROP VIEW IF EXISTS {{table_name_prefix}}_slice_in_frame;
CREATE VIEW {{table_name_prefix}}_slice_in_frame AS
SELECT
frame.*,
query_slice.id AS slice_id,
query_slice.utid AS slice_utid,
query_slice.name AS slice_name,
MAX(query_slice.ts, frame_boundary.ts) AS slice_ts,
MIN(query_slice.ts_end, frame_boundary.ts_end) AS slice_ts_end,
MIN(query_slice.ts_end, frame_boundary.ts_end) - MAX(query_slice.ts, frame_boundary.ts) AS slice_dur,
query_slice.ts_end AS ts_end_original
FROM {{frame_table_name}} frame
-- We want to use different boundaries depending on which thread's slices the query is targetting.
JOIN {{frame_boundary_table_name}} frame_boundary USING (cuj_id, vsync)
JOIN {{table_name_prefix}}_query_slice query_slice
ON frame_boundary.cuj_id = query_slice.cuj_id
AND ANDROID_JANK_CUJ_SLICE_OVERLAPS(frame_boundary.ts, frame_boundary.dur, query_slice.ts, query_slice.dur);
-- Aggregated view of frames and slices overall durations within each frame boundaries.
DROP VIEW IF EXISTS {{table_name_prefix}}_slice_in_frame_agg;
CREATE VIEW {{table_name_prefix}}_slice_in_frame_agg AS
SELECT
cuj_id,
frame_number,
vsync,
dur_expected,
app_missed,
sf_missed,
1.0 * SUM(slice_dur) / dur_expected AS slice_dur_div_frame_dur_expected,
SUM(slice_dur) AS slice_dur_sum,
MAX(slice_dur) AS slice_dur_max
FROM {{table_name_prefix}}_slice_in_frame
GROUP BY cuj_id, frame_number, vsync, dur_expected, app_missed, sf_missed;