blob: 7c56db21421263ad4127088ee6279586c4a09d97 [file] [log] [blame]
--
-- Copyright 2023 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.
-- Create the base table (`android_jank_cuj`) containing all completed CUJs
-- found in the trace.
-- This script will use the `android_jank_cuj_main_thread_cuj_boundary`,
-- containing bounds of jank CUJs.
SELECT RUN_METRIC('android/android_jank_cuj.sql');
SELECT IMPORT('android.slices');
-- Jank "J<*>" and latency "L<*>" cujs are put together in android_cujs table.
-- They are computed separately as latency ones are slightly different, don't
-- currently have the same way to be cancelled, and are not anchored to vsyncs.
DROP TABLE IF EXISTS android_cujs;
CREATE TABLE android_cujs AS
WITH latency_cujs AS (
SELECT
ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id,
process.upid AS upid,
process.name AS process_name,
process_metadata.metadata AS process_metadata,
-- Extracts "CUJ_NAME" from "L<CUJ_NAME>"
SUBSTR(slice.name, 3, LENGTH(slice.name) - 3) AS cuj_name,
ts,
dur,
ts + dur AS ts_end,
'completed' AS state
FROM slice
JOIN process_track
ON slice.track_id = process_track.id
JOIN process USING (upid)
JOIN process_metadata USING (upid)
WHERE
slice.name GLOB 'L<*>'
AND dur > 0
),
all_cujs AS (
SELECT
cuj_id,
upid,
process_name,
process_metadata,
cuj_name,
tb.ts,
tb.dur,
tb.ts_end
FROM android_jank_cuj_main_thread_cuj_boundary tb
JOIN android_jank_cuj using (cuj_id)
UNION
SELECT
cuj_id,
upid,
process_name,
process_metadata,
cuj_name,
ts,
dur,
ts_end
FROM latency_cujs
)
SELECT ROW_NUMBER() OVER (ORDER BY ts) AS cuj_id, *
FROM all_cujs;
DROP TABLE IF EXISTS android_blocking_calls_cuj_calls;
CREATE TABLE android_blocking_calls_cuj_calls AS
WITH all_main_thread_relevant_slices AS (
SELECT DISTINCT
ANDROID_STANDARDIZE_SLICE_NAME(s.name) AS name,
s.ts,
s.track_id,
s.dur,
s.id,
process.name AS process_name,
thread.utid,
process.upid
FROM slice s
JOIN thread_track ON s.track_id = thread_track.id
JOIN thread USING (utid)
JOIN process USING (upid)
JOIN android_cujs USING (upid) -- Keeps only slices in cuj processes.
WHERE
thread.is_main_thread AND (
s.name = 'measure'
OR s.name = 'layout'
OR s.name = 'configChanged'
OR s.name = 'Contending for pthread mutex'
OR s.name GLOB 'monitor contention with*'
OR s.name GLOB 'SuspendThreadByThreadId*'
OR s.name GLOB 'LoadApkAssetsFd*'
OR s.name GLOB '*binder transaction*'
OR s.name GLOB 'inflate*'
OR s.name GLOB 'Lock contention on*'
OR s.name GLOB '*CancellableContinuationImpl*'
OR s.name GLOB 'relayoutWindow*'
OR s.name GLOB 'ImageDecoder#decode*'
)
),
-- Now we have:
-- (1) a list of slices from the main thread of each process
-- (2) a list of android cuj with beginning, end, and process
-- It's needed to:
-- (1) assign a cuj to each slice. If there are multiple cujs going on during a
-- slice, there needs to be 2 entries for that slice, one for each cuj id.
-- (2) each slice needs to be trimmed to be fully inside the cuj associated
-- (as we don't care about what's outside cujs)
main_thread_slices_scoped_to_cujs AS (
SELECT
s.id,
s.id AS slice_id,
s.track_id,
s.name,
max(s.ts, cuj.ts) AS ts,
min(s.ts + s.dur, cuj.ts_end) as ts_end,
min(s.ts + s.dur, cuj.ts_end) - max(s.ts, cuj.ts) AS dur,
cuj.cuj_id,
cuj.cuj_name,
s.process_name,
s.upid,
s.utid
FROM all_main_thread_relevant_slices s
JOIN android_cujs cuj
-- only when there is an overlap
ON s.ts + s.dur > cuj.ts AND s.ts < cuj.ts_end
-- and are from the same process
AND s.upid = cuj.upid
)
SELECT
name,
COUNT(*) AS occurrences,
CAST(MAX(dur) / 1e6 AS INT) AS max_dur_ms,
CAST(MIN(dur) / 1e6 AS INT) AS min_dur_ms,
CAST(SUM(dur) / 1e6 AS INT) AS total_dur_ms,
upid,
cuj_id,
cuj_name,
process_name
FROM
main_thread_slices_scoped_to_cujs
GROUP BY name, upid, cuj_id, cuj_name, process_name
ORDER BY cuj_id;
DROP VIEW IF EXISTS android_blocking_calls_cuj_metric_output;
CREATE VIEW android_blocking_calls_cuj_metric_output AS
SELECT AndroidBlockingCallsCujMetric('cuj', (
SELECT RepeatedField(
AndroidBlockingCallsCujMetric_Cuj(
'id', cuj_id,
'name', cuj_name,
'process', process_metadata,
'ts', cuj.ts,
'dur', cuj.dur,
'blocking_calls', (
SELECT RepeatedField(
AndroidBlockingCallsCujMetric_BlockingCall(
'name', b.name,
'cnt', b.occurrences,
'total_dur_ms', b.total_dur_ms,
'max_dur_ms', b.max_dur_ms,
'min_dur_ms', b.min_dur_ms
)
)
FROM android_blocking_calls_cuj_calls b
WHERE b.cuj_id = cuj.cuj_id and b.upid = cuj.upid
ORDER BY total_dur_ms DESC
)
)
)
FROM android_cujs cuj
ORDER BY cuj.cuj_id ASC
));