blob: da5951a6b12818285268994bbf523228c6210c92 [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.
SELECT CREATE_FUNCTION(
'VSYNC_FROM_NAME(slice_name STRING)',
'STRING',
'SELECT CAST(STR_SPLIT($slice_name, " ", 1) AS INTEGER)'
);
SELECT CREATE_FUNCTION(
'GPU_COMPLETION_FENCE_ID_FROM_NAME(slice_name STRING)',
'STRING',
'SELECT
CASE
WHEN
$slice_name GLOB "GPU completion fence *"
THEN
CAST(STR_SPLIT($slice_name, " ", 3) AS INTEGER)
WHEN
$slice_name GLOB "Trace GPU completion fence *"
THEN
CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
WHEN
$slice_name GLOB "waiting for GPU completion *"
THEN
CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
WHEN
$slice_name GLOB "Trace HWC release fence *"
THEN
CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
WHEN
$slice_name GLOB "waiting for HWC release *"
THEN
CAST(STR_SPLIT($slice_name, " ", 4) AS INTEGER)
ELSE NULL
END
'
);
-- Find Choreographer#doFrame slices that are between the CUJ markers.
-- We extract vsync IDs from doFrame slice names and use these as the source
-- of truth that allow us to get correct slices on the other threads.
DROP TABLE IF EXISTS android_jank_cuj_do_frame_slice;
CREATE TABLE android_jank_cuj_do_frame_slice AS
SELECT
cuj.cuj_id,
main_thread.upid,
main_thread.utid,
slice.*,
slice.ts + slice.dur AS ts_end,
VSYNC_FROM_NAME(slice.name) AS vsync
FROM android_jank_cuj cuj
JOIN slice
ON slice.ts + slice.dur >= cuj.ts AND slice.ts <= cuj.ts_end
JOIN android_jank_cuj_main_thread main_thread
ON cuj.cuj_id = main_thread.cuj_id
AND main_thread.track_id = slice.track_id
WHERE
slice.name GLOB 'Choreographer#doFrame*'
-- Ignore child slice e.g. "Choreographer#doFrame - resynced to 1234 in 20.0ms"
AND slice.name not GLOB '*resynced*'
AND slice.dur > 0;
-- Store render thread DrawFrames by matching in the vsync IDs extracted from
-- doFrame slices. In case of multiple layers being drawn, there might be
-- multiple DrawFrames for a single vsync.
DROP TABLE IF EXISTS android_jank_cuj_draw_frame_slice;
CREATE TABLE android_jank_cuj_draw_frame_slice AS
SELECT
cuj_id,
render_thread.upid,
render_thread.utid,
slice.*,
slice.ts + slice.dur AS ts_end,
VSYNC_FROM_NAME(slice.name) AS vsync
FROM android_jank_cuj_do_frame_slice do_frame
JOIN android_jank_cuj_render_thread render_thread USING (cuj_id)
JOIN slice
ON slice.track_id = render_thread.track_id
WHERE slice.name GLOB 'DrawFrame*'
AND VSYNC_FROM_NAME(slice.name) = do_frame.vsync
AND slice.dur > 0;
-- Find descendants of DrawFrames which contain the GPU completion fence ID that
-- is used for signaling that the GPU finished drawing.
DROP TABLE IF EXISTS android_jank_cuj_gpu_completion_fence;
CREATE TABLE android_jank_cuj_gpu_completion_fence AS
SELECT
cuj_id,
vsync,
draw_frame.id AS draw_frame_slice_id,
GPU_COMPLETION_FENCE_ID_FROM_NAME(fence.name) AS fence_idx
FROM android_jank_cuj_draw_frame_slice draw_frame
JOIN descendant_slice(draw_frame.id) fence
ON fence.name GLOB '*GPU completion fence*';
-- Similarly find descendants of DrawFrames which have the HWC release fence ID
DROP TABLE IF EXISTS android_jank_cuj_hwc_release_fence;
CREATE TABLE android_jank_cuj_hwc_release_fence AS
SELECT
cuj_id,
vsync,
draw_frame.id AS draw_frame_slice_id,
GPU_COMPLETION_FENCE_ID_FROM_NAME(fence.name) AS fence_idx
FROM android_jank_cuj_draw_frame_slice draw_frame
JOIN descendant_slice(draw_frame.id) fence
ON fence.name GLOB '*HWC release fence *';
-- Find HWC release slices which indicate when the HWC released the buffer.
DROP TABLE IF EXISTS android_jank_cuj_hwc_release_slice;
CREATE TABLE android_jank_cuj_hwc_release_slice AS
SELECT
fence.cuj_id,
vsync,
slice.*,
slice.ts + slice.dur AS ts_end,
fence.fence_idx,
draw_frame_slice_id
FROM android_jank_cuj_hwc_release_thread hwc_release_thread
JOIN slice USING (track_id)
JOIN android_jank_cuj_hwc_release_fence fence
ON fence.cuj_id = hwc_release_thread.cuj_id
AND fence.fence_idx = GPU_COMPLETION_FENCE_ID_FROM_NAME(slice.name)
WHERE
slice.name GLOB 'waiting for HWC release *'
AND slice.dur > 0;
-- Find GPU completion slices which indicate when the GPU finished drawing.
DROP TABLE IF EXISTS android_jank_cuj_gpu_completion_slice;
CREATE TABLE android_jank_cuj_gpu_completion_slice AS
SELECT
fence.cuj_id,
vsync,
slice.*,
slice.ts + slice.dur AS ts_end,
hwc_release.ts_end AS hwc_release_ts_end,
fence.fence_idx
FROM android_jank_cuj_gpu_completion_thread gpu_completion_thread
JOIN slice USING (track_id)
JOIN android_jank_cuj_gpu_completion_fence fence
ON fence.cuj_id = gpu_completion_thread.cuj_id
AND fence.fence_idx = GPU_COMPLETION_FENCE_ID_FROM_NAME(slice.name)
LEFT JOIN android_jank_cuj_hwc_release_slice hwc_release
USING (cuj_id, vsync, draw_frame_slice_id)
WHERE
slice.name GLOB 'waiting for GPU completion *'
AND slice.dur > 0;
-- Match the frame timeline on the app side with the frame timeline on the SF side.
-- This way we get the vsyncs IDs of SF frames within the CUJ.
-- Note that there might be multiple SF vsync IDs that match a single App vsync ID, e.g.
-- if one App layer produced a frame later and it was picked up by the next SF frame.
DROP TABLE IF EXISTS android_jank_cuj_app_to_sf_match;
CREATE TABLE android_jank_cuj_app_to_sf_match AS
SELECT
cuj_id,
do_frame.upid AS app_upid,
do_frame.vsync AS app_vsync,
sf_process.upid AS sf_upid,
CAST(sf_timeline.name AS INTEGER) AS sf_vsync
FROM android_jank_cuj_do_frame_slice do_frame
JOIN actual_frame_timeline_slice app_timeline
ON do_frame.upid = app_timeline.upid
AND do_frame.vsync = CAST(app_timeline.name AS INTEGER)
JOIN directly_connected_flow(app_timeline.id) flow
ON flow.slice_in = app_timeline.id
JOIN actual_frame_timeline_slice sf_timeline
ON flow.slice_out = sf_timeline.id
JOIN android_jank_cuj_sf_process sf_process
ON sf_timeline.upid = sf_process.upid
-- In cases where there are multiple layers drawn we would have separate frame timeline
-- slice for each of the layers. GROUP BY to deduplicate these rows.
GROUP BY cuj_id, app_upid, app_vsync, sf_upid, sf_vsync;
SELECT CREATE_VIEW_FUNCTION(
'ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE(slice_name_glob STRING)',
'cuj_id INT, utid INT, vsync INT, id INT, name STRING, ts LONG, dur LONG, ts_end LONG',
'
WITH sf_vsync AS (
SELECT DISTINCT cuj_id, sf_vsync AS vsync
FROM android_jank_cuj_app_to_sf_match)
SELECT
cuj_id,
utid,
sf_vsync.vsync,
slice.id,
slice.name,
slice.ts,
slice.dur,
slice.ts + slice.dur AS ts_end
FROM slice
JOIN android_jank_cuj_sf_main_thread main_thread USING (track_id)
JOIN sf_vsync
ON VSYNC_FROM_NAME(slice.name) = sf_vsync.vsync
WHERE slice.name GLOB $slice_name_glob AND slice.dur > 0
ORDER BY cuj_id, vsync;
'
);
DROP TABLE IF EXISTS android_jank_cuj_sf_commit_slice;
CREATE TABLE android_jank_cuj_sf_commit_slice AS
SELECT * FROM ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE('commit *');
DROP TABLE IF EXISTS android_jank_cuj_sf_composite_slice;
CREATE TABLE android_jank_cuj_sf_composite_slice AS
SELECT * FROM ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE('composite *');
-- Older builds do not have the commit/composite but onMessageInvalidate instead
DROP TABLE IF EXISTS android_jank_cuj_sf_on_message_invalidate_slice;
CREATE TABLE android_jank_cuj_sf_on_message_invalidate_slice AS
SELECT * FROM ANDROID_JANK_CUJ_SF_MAIN_THREAD_SLICE('onMessageInvalidate *');
DROP VIEW IF EXISTS android_jank_cuj_sf_root_slice;
CREATE VIEW android_jank_cuj_sf_root_slice AS
SELECT * FROM android_jank_cuj_sf_commit_slice
UNION ALL
SELECT * FROM android_jank_cuj_sf_composite_slice
UNION ALL
SELECT * FROM android_jank_cuj_sf_on_message_invalidate_slice;
-- Find descendants of SF main thread slices which contain the GPU completion fence ID that
-- is used for signaling that the GPU finished drawing.
DROP TABLE IF EXISTS android_jank_cuj_sf_gpu_completion_fence;
CREATE TABLE android_jank_cuj_sf_gpu_completion_fence AS
SELECT
cuj_id,
vsync,
sf_root_slice.id AS sf_root_slice_id,
GPU_COMPLETION_FENCE_ID_FROM_NAME(fence.name) AS fence_idx
FROM android_jank_cuj_sf_root_slice sf_root_slice
JOIN descendant_slice(sf_root_slice.id) fence
ON fence.name GLOB '*GPU completion fence*';
-- Find GPU completion slices which indicate when the GPU finished drawing.
DROP TABLE IF EXISTS android_jank_cuj_sf_gpu_completion_slice;
CREATE TABLE android_jank_cuj_sf_gpu_completion_slice AS
SELECT
fence.cuj_id,
vsync,
slice.*,
slice.ts + slice.dur AS ts_end,
fence.fence_idx
FROM android_jank_cuj_sf_gpu_completion_fence fence
JOIN android_jank_cuj_sf_gpu_completion_thread gpu_completion_thread
JOIN slice
ON slice.track_id = gpu_completion_thread.track_id
AND fence.fence_idx = GPU_COMPLETION_FENCE_ID_FROM_NAME(slice.name)
WHERE
slice.name GLOB 'waiting for GPU completion *'
AND slice.dur > 0;
-- Find REThreaded::drawLayers on RenderEngine thread.
-- These will be only relevant if SF is doing client composition so we check if
-- the drawLayers slice is completely within the bounds of composeSurfaces on SF
-- main thread.
DROP TABLE IF EXISTS android_jank_cuj_sf_draw_layers_slice;
CREATE TABLE android_jank_cuj_sf_draw_layers_slice AS
WITH compose_surfaces AS (
SELECT
cuj_id,
vsync,
sf_root_slice.id AS sf_root_slice_id,
compose_surfaces.ts,
compose_surfaces.ts + compose_surfaces.dur AS ts_end
FROM android_jank_cuj_sf_root_slice sf_root_slice
JOIN descendant_slice(sf_root_slice.id) compose_surfaces
ON compose_surfaces.name = 'composeSurfaces'
)
SELECT
cuj_id,
re_thread.utid,
vsync,
draw_layers.*,
draw_layers.ts + draw_layers.dur AS ts_end,
-- Store composeSurfaces ts as this will simplify calculating frame boundaries
compose_surfaces.ts AS ts_compose_surfaces
FROM compose_surfaces
JOIN android_jank_cuj_sf_render_engine_thread re_thread
JOIN slice draw_layers
ON draw_layers.track_id = re_thread.track_id
AND draw_layers.ts >= compose_surfaces.ts
AND draw_layers.ts + draw_layers.dur <= compose_surfaces.ts_end
WHERE
draw_layers.name = 'REThreaded::drawLayers'
AND draw_layers.dur > 0;