aboutsummaryrefslogtreecommitdiff
path: root/src/trace_processor/metrics/sql/android/jank/frames.sql
blob: ffef19d7f97ba7123dd423473b7a1766d9759e0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
--
-- 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.

DROP TABLE IF EXISTS vsync_missed_callback;
CREATE TABLE vsync_missed_callback AS
SELECT CAST(STR_SPLIT(name, 'Callback#', 1) AS INTEGER) AS vsync,
       MAX(name GLOB '*SF*') as sf_callback_missed,
       MAX(name GLOB '*HWUI*') as hwui_callback_missed
FROM slice
WHERE name GLOB '*FT#Missed*Callback*'
GROUP BY vsync;

DROP TABLE IF EXISTS android_jank_cuj_frame_timeline;
CREATE TABLE android_jank_cuj_frame_timeline AS
WITH actual_timeline_with_vsync AS (
  SELECT
    *,
    CAST(name AS INTEGER) AS vsync
  FROM actual_frame_timeline_slice
  WHERE dur > 0
)
SELECT
  cuj_id,
  vsync,
  -- We use MAX to check if at least one of the layers jank_type matches the pattern
  MAX(jank_type GLOB '*App Deadline Missed*') AS app_missed,
  -- We use MAX to check if at least one of the layers jank_type matches the pattern
  MAX(
    jank_type GLOB '*SurfaceFlinger CPU Deadline Missed*'
    OR jank_type GLOB '*SurfaceFlinger GPU Deadline Missed*'
    OR jank_type GLOB '*SurfaceFlinger Scheduling*'
    OR jank_type GLOB '*Prediction Error*'
    OR jank_type GLOB '*Display HAL*') AS sf_missed,
  IFNULL(MAX(sf_callback_missed), 0) AS sf_callback_missed,
  IFNULL(MAX(hwui_callback_missed), 0) AS hwui_callback_missed,
  -- We use MIN to check if ALL layers finished on time
  MIN(on_time_finish) AS on_time_finish,
  MAX(timeline.ts + timeline.dur) AS ts_end_actual,
  MAX(timeline.dur) AS dur,
  -- At the moment of writing we expect to see at most one expected_frame_timeline_slice
  -- for a given vsync but using MAX here in case this changes in the future.
  -- In case expected timeline is missing, as a fallback we use the typical frame deadline
  -- for 60Hz.
  COALESCE(MAX(expected.dur), 16600000) AS dur_expected,
  COUNT(DISTINCT timeline.layer_name) as number_of_layers_for_frame,
  -- we use MAX to get at least one of the frame's layer names
  MAX(timeline.layer_name) as frame_layer_name
FROM android_jank_cuj_vsync_boundary boundary
JOIN actual_timeline_with_vsync timeline
  ON boundary.upid = timeline.upid
    AND vsync >= vsync_min
    AND vsync <= vsync_max
LEFT JOIN expected_frame_timeline_slice expected
  ON expected.upid = timeline.upid AND expected.name = timeline.name
LEFT JOIN vsync_missed_callback missed_callback USING(vsync)
WHERE
  boundary.layer_id IS NULL
  OR (
    timeline.layer_name GLOB '*#*'
    AND boundary.layer_id
      = CAST(STR_SPLIT(timeline.layer_name, '#', 1) AS INTEGER))
GROUP BY cuj_id, vsync;

DROP TABLE IF EXISTS android_jank_cuj_layer_name;
CREATE TABLE android_jank_cuj_layer_name AS
SELECT
    cuj_id,
    MAX(frame_layer_name) as layer_name
FROM android_jank_cuj_frame_timeline timeline
GROUP BY cuj_id
-- Return only cujs where the max number of layers for all frames in the whole cuj equals 1,
-- this is to infer the layer name if the cuj marker for layer id is not present
HAVING MAX(number_of_layers_for_frame) = 1;

-- Matches slices and boundaries to compute estimated frame boundaries across
-- all threads. Joins with the actual timeline to figure out which frames missed
-- the deadline and whether the app process or SF are at fault.
DROP TABLE IF EXISTS android_jank_cuj_frame;
CREATE TABLE android_jank_cuj_frame AS
WITH frame_base AS (
  SELECT
    cuj_id,
    ROW_NUMBER() OVER (PARTITION BY cuj_id ORDER BY do_frame.vsync ASC) AS frame_number,
    vsync,
    boundary.ts,
    boundary.ts_expected,
    boundary.ts_do_frame_start,
    COUNT(fence_idx) AS gpu_fence_count,
    COUNT(fence_idx) > 0 AS drew_anything
  FROM android_jank_cuj_do_frame_slice do_frame
  JOIN android_jank_cuj_main_thread_frame_boundary boundary USING (cuj_id, vsync)
  JOIN android_jank_cuj_draw_frame_slice draw_frame USING (cuj_id, vsync)
  LEFT JOIN android_jank_cuj_gpu_completion_fence fence USING (cuj_id, vsync)
  WHERE draw_frame.id = fence.draw_frame_slice_id
  GROUP BY cuj_id, vsync, boundary.ts, boundary.ts_do_frame_start
)
SELECT
  frame_base.*,
  app_missed,
  sf_missed,
  sf_callback_missed,
  hwui_callback_missed,
  on_time_finish,
  ts_end_actual - ts AS dur,
  ts_end_actual - ts_do_frame_start AS dur_unadjusted,
  dur_expected,
  ts_end_actual AS ts_end
FROM frame_base
JOIN android_jank_cuj_frame_timeline USING (cuj_id, vsync);

-- Similar to `android_jank_cuj_frame` computes overall SF frame boundaries.
-- The computation is somewhat simpler as most of SF work happens within the duration of
-- the commit/composite slices on the main thread.
DROP TABLE IF EXISTS android_jank_cuj_sf_frame;
CREATE TABLE android_jank_cuj_sf_frame AS
SELECT
  cuj_id,
  ROW_NUMBER() OVER (PARTITION BY cuj_id ORDER BY vsync ASC) AS frame_number,
  vsync,
  boundary.ts,
  boundary.ts_main_thread_start,
  boundary.ts_end,
  boundary.dur,
  actual_timeline.jank_tag = 'Self Jank' AS sf_missed,
  NULL AS app_missed, -- for simplicity align schema with android_jank_cuj_frame
  jank_tag,
  jank_type,
  prediction_type,
  present_type,
  gpu_composition,
  -- In case expected timeline is missing, as a fallback we use the typical frame deadline
  -- for 60Hz.
  -- See similar expression in android_jank_cuj_frame_timeline.
  COALESCE(expected_timeline.dur, 16600000) AS dur_expected
FROM android_jank_cuj_sf_main_thread_frame_boundary boundary
JOIN android_jank_cuj_sf_process sf_process
JOIN actual_frame_timeline_slice actual_timeline
  ON actual_timeline.upid = sf_process.upid
    AND boundary.vsync = CAST(actual_timeline.name AS INTEGER)
LEFT JOIN expected_frame_timeline_slice expected_timeline
  ON expected_timeline.upid = actual_timeline.upid
    AND expected_timeline.name = actual_timeline.name;