• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1-- Isolate the SurfaceFlinger process Id
2DROP TABLE IF EXISTS android_sysui_cuj_sf_process;
3CREATE TABLE android_sysui_cuj_sf_process AS
4SELECT name, upid FROM process
5WHERE process.name='/system/bin/surfaceflinger'
6LIMIT 1;
7
8DROP VIEW IF EXISTS android_sysui_cuj_sf_actual_frame_timeline_slice;
9CREATE VIEW android_sysui_cuj_sf_actual_frame_timeline_slice AS
10SELECT
11  actual.*,
12  actual.ts + actual.dur AS ts_end,
13  CAST(actual.name AS integer) AS vsync
14FROM actual_frame_timeline_slice actual JOIN android_sysui_cuj_sf_process USING (upid);
15
16DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_main_thread;
17CREATE TABLE android_sysui_cuj_surfaceflinger_main_thread AS
18  SELECT android_sysui_cuj_sf_process.name AS process_name, thread.utid
19  FROM thread JOIN android_sysui_cuj_sf_process USING (upid)
20  WHERE thread.is_main_thread;
21
22DROP TABLE IF EXISTS android_sysui_cuj_sf_main_thread_track;
23CREATE TABLE android_sysui_cuj_sf_main_thread_track AS
24SELECT thread_track.id
25FROM thread_track
26JOIN android_sysui_cuj_surfaceflinger_main_thread thread USING (utid);
27
28DROP VIEW IF EXISTS android_sysui_cuj_surfaceflinger_gpu_completion_thread;
29CREATE VIEW android_sysui_cuj_surfaceflinger_gpu_completion_thread AS
30  SELECT android_sysui_cuj_sf_process.name AS process_name, thread.utid
31  FROM thread JOIN android_sysui_cuj_sf_process USING (upid)
32  WHERE thread.name = 'GPU completion';
33
34DROP VIEW IF EXISTS android_sysui_cuj_surfaceflinger_renderengine_thread;
35CREATE VIEW android_sysui_cuj_surfaceflinger_renderengine_thread AS
36  SELECT android_sysui_cuj_sf_process.name AS process_name, thread.utid
37  FROM thread JOIN android_sysui_cuj_sf_process USING (upid)
38  WHERE thread.name = 'RenderEngine';
39
40DROP VIEW IF EXISTS android_sysui_cuj_surfaceflinger_gpu_completion_slices;
41CREATE VIEW android_sysui_cuj_surfaceflinger_gpu_completion_slices AS
42  SELECT
43    process_name,
44    thread.utid,
45    slice.*,
46    slice.ts + slice.dur AS ts_end,
47    -- Extracts 1234 from 'waiting for GPU completion 1234'
48    CAST(STR_SPLIT(slice.name, ' ', 4) AS INTEGER) AS idx
49  FROM slice
50  JOIN thread_track ON slice.track_id = thread_track.id
51  JOIN android_sysui_cuj_surfaceflinger_gpu_completion_thread thread USING (utid)
52  WHERE slice.name GLOB 'waiting for GPU completion *'
53  AND dur > 0;
54
55-- Find flows between actual frame slices from app process to surfaceflinger, allowing us to
56-- correlate vsyncs.
57DROP VIEW IF EXISTS android_sysui_cuj_surfaceflinger_app_flow_vsyncs;
58CREATE VIEW android_sysui_cuj_surfaceflinger_app_flow_vsyncs AS
59SELECT
60  app_slice.name AS app_vsync,
61  app_slice.id AS app_slice_id,
62  cuj_process.name AS app_process,
63  sf_slice.name AS sf_vsync,
64  sf_slice.id AS sf_slice_id
65FROM android_sysui_cuj_sf_actual_frame_timeline_slice sf_slice
66JOIN directly_connected_flow(sf_slice.id) flow
67JOIN actual_frame_timeline_slice app_slice ON slice_in = app_slice.id
68JOIN android_sysui_cuj_last_cuj cuj_process ON app_slice.upid = cuj_process.upid
69GROUP BY app_vsync, sf_vsync;
70
71-- Filter to those SF frames which flow from app frames that are within the app vsync boundaries of
72-- the CUJ
73DROP TABLE IF EXISTS android_sysui_cuj_sf_frames_in_cuj;
74CREATE TABLE android_sysui_cuj_sf_frames_in_cuj AS
75SELECT
76  sf_frame.ts,
77  sf_frame.dur,
78  sf_frame.jank_type,
79  sf_frame.ts + sf_frame.dur AS ts_end,
80  flows.sf_vsync,
81  flows.app_vsync
82-- This table contains only the frame timeline slices within the CUJ app vsync boundaries
83FROM android_sysui_cuj_frame_timeline_events app_frames
84-- Find the matching SF frame via flow
85JOIN android_sysui_cuj_surfaceflinger_app_flow_vsyncs flows ON app_frames.vsync = flows.app_vsync
86JOIN android_sysui_cuj_sf_actual_frame_timeline_slice sf_frame ON sf_frame.id = flows.sf_slice_id
87GROUP BY flows.sf_vsync;
88
89-- Take the min and max vsync to define the SurfaceFlinger boundaries
90DROP TABLE IF EXISTS android_sysui_cuj_sf_vsync_boundaries;
91CREATE TABLE android_sysui_cuj_sf_vsync_boundaries AS
92SELECT MIN(sf_vsync) AS vsync_min, MAX(sf_vsync) AS vsync_max
93FROM android_sysui_cuj_sf_frames_in_cuj;
94
95-- Find just the commit slices, within the CUJ (by vsync)
96DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_commit_slices_in_cuj;
97CREATE TABLE android_sysui_cuj_surfaceflinger_commit_slices_in_cuj AS
98SELECT * FROM
99  (SELECT
100    -- Extract the vsync number from name like 'commit 235991 vsyncIn 15.992ms'
101    CAST(STR_SPLIT(slice.name, ' ', 1) AS INTEGER) AS vsync,
102    CAST(CAST(STR_SPLIT(slice.name, ' ', 3) AS NUMBER) * 1e6 + slice.ts AS INTEGER) AS expected_vsync_ts,
103    slice.name,
104    slice.ts,
105    slice.dur,
106    slice.ts + slice.dur AS ts_end
107  FROM slice
108  JOIN android_sysui_cuj_sf_main_thread_track main_track ON slice.track_id = main_track.id
109  WHERE slice.dur > 0 AND slice.name GLOB 'commit *')
110JOIN android_sysui_cuj_sf_vsync_boundaries cuj_boundaries
111WHERE vsync >= cuj_boundaries.vsync_min AND vsync <= cuj_boundaries.vsync_max;
112
113-- Find just the onMessageInvalidate slices, within the CUJ (by vsync)
114DROP VIEW IF EXISTS android_sysui_cuj_surfaceflinger_on_message_invalidate_slices_in_cuj;
115CREATE VIEW android_sysui_cuj_surfaceflinger_on_message_invalidate_slices_in_cuj AS
116  WITH on_msg AS (SELECT
117    -- Extract the vsync number from name like 'onMessageInvalidate 235991 vsyncIn 15.992ms'
118    CAST(STR_SPLIT(slice.name, ' ', 1) AS INTEGER) AS vsync,
119    CAST(CAST(STR_SPLIT(slice.name, ' ', 3) AS NUMBER) * 1e6 + slice.ts AS INTEGER) AS expected_vsync_ts,
120    slice.ts,
121    slice.ts + slice.dur AS ts_end,
122    slice.dur
123  FROM slice
124  JOIN android_sysui_cuj_sf_main_thread_track main_track ON slice.track_id = main_track.id
125  WHERE slice.name GLOB 'onMessageInvalidate *'
126  )
127SELECT
128    on_msg.vsync,
129    on_msg.ts,
130    on_msg.ts_end,
131    on_msg.dur,
132    on_msg.expected_vsync_ts,
133    lag(on_msg.ts_end) OVER (ORDER BY on_msg.ts_end ASC) AS ts_prev_frame_end,
134    lead(on_msg.ts) OVER (ORDER BY on_msg.ts ASC) AS ts_next_frame_start
135FROM on_msg
136JOIN android_sysui_cuj_sf_vsync_boundaries cuj_boundaries
137WHERE on_msg.vsync >= cuj_boundaries.vsync_min AND on_msg.vsync <= cuj_boundaries.vsync_max;
138
139-- Find just the composite slices
140DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_composite_slices;
141CREATE TABLE android_sysui_cuj_surfaceflinger_composite_slices AS
142  SELECT
143    slice.name,
144    slice.ts,
145    slice.dur,
146    slice.ts + slice.dur AS ts_end
147  FROM slice
148  JOIN android_sysui_cuj_sf_main_thread_track main_track ON slice.track_id = main_track.id
149  WHERE slice.dur > 0 AND slice.name = 'composite';
150
151DROP VIEW IF EXISTS android_sysui_cuj_surfaceflinger_commit_composite_frames_in_cuj;
152CREATE VIEW android_sysui_cuj_surfaceflinger_commit_composite_frames_in_cuj AS
153  WITH commit_to_composite AS (
154    SELECT
155      commits.vsync,
156      commits.ts AS commit_ts,
157      commits.name AS name,
158      commits.expected_vsync_ts,
159      min(composite.ts) AS composite_ts
160      FROM android_sysui_cuj_surfaceflinger_commit_slices_in_cuj commits
161      JOIN android_sysui_cuj_surfaceflinger_composite_slices composite ON composite.ts > commits.ts_end
162      GROUP BY commits.vsync
163  )
164  SELECT
165    vsync,
166    match.commit_ts AS ts,
167    composite.ts_end AS ts_end,
168    composite.ts_end - match.commit_ts AS dur,
169    match.expected_vsync_ts,
170    lag(composite.ts_end) OVER (ORDER BY composite.ts_end ASC) AS ts_prev_frame_end,
171    lead(match.commit_ts) OVER (ORDER BY match.commit_ts ASC) AS ts_next_frame_start
172  FROM commit_to_composite match
173  JOIN android_sysui_cuj_surfaceflinger_composite_slices composite ON match.composite_ts = composite.ts;
174
175-- All SF frames in the CUJ
176DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_main_thread_frames;
177CREATE TABLE android_sysui_cuj_surfaceflinger_main_thread_frames AS
178SELECT * FROM android_sysui_cuj_surfaceflinger_on_message_invalidate_slices_in_cuj
179UNION ALL
180SELECT * FROM android_sysui_cuj_surfaceflinger_commit_composite_frames_in_cuj;
181
182-- Our timestamp boundaries are the earliest ts and latest ts_end of the main thread frames (e.g.
183-- onMessageInvalidate or commit/composite pair) which flow from app frames within the CUJ
184DROP TABLE IF EXISTS android_sysui_cuj_sf_ts_boundaries;
185CREATE TABLE android_sysui_cuj_sf_ts_boundaries AS
186SELECT ts, ts_end - ts AS dur, ts_end
187FROM (SELECT MIN(ts) AS ts, MAX(ts_end) AS ts_end FROM android_sysui_cuj_surfaceflinger_main_thread_frames);
188
189DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_main_thread_slices_in_cuj;
190CREATE TABLE android_sysui_cuj_surfaceflinger_main_thread_slices_in_cuj AS
191  SELECT
192    slice.*,
193    slice.ts + slice.dur AS ts_end
194  FROM slice
195  JOIN android_sysui_cuj_sf_main_thread_track main_track ON slice.track_id = main_track.id
196  JOIN android_sysui_cuj_sf_ts_boundaries cuj_boundaries
197  ON slice.ts >= cuj_boundaries.ts AND slice.ts <= cuj_boundaries.ts_end
198  WHERE slice.dur > 0;
199
200-- Find SurfaceFlinger GPU completions that are within the CUJ
201DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_gpu_completion_slices_in_cuj;
202CREATE TABLE android_sysui_cuj_surfaceflinger_gpu_completion_slices_in_cuj AS
203SELECT slice.* FROM android_sysui_cuj_surfaceflinger_gpu_completion_slices slice
204JOIN android_sysui_cuj_sf_ts_boundaries cuj_boundaries
205ON slice.ts >= cuj_boundaries.ts AND slice.ts <= cuj_boundaries.ts_end;
206
207DROP TABLE IF EXISTS android_sysui_cuj_surfaceflinger_renderengine_slices_in_cuj;
208CREATE TABLE android_sysui_cuj_surfaceflinger_renderengine_slices_in_cuj AS
209  SELECT
210    process_name,
211    thread.utid,
212    slice.*,
213    slice.ts + slice.dur AS ts_end
214  FROM slice
215  JOIN thread_track ON slice.track_id = thread_track.id
216  JOIN android_sysui_cuj_surfaceflinger_renderengine_thread thread USING (utid)
217  JOIN android_sysui_cuj_sf_ts_boundaries cuj_boundaries
218  ON slice.ts >= cuj_boundaries.ts AND slice.ts <= cuj_boundaries.ts_end
219  WHERE slice.dur > 0;
220
221DROP VIEW IF EXISTS android_sysui_cuj_gcs_to_mt_match;
222CREATE VIEW android_sysui_cuj_gcs_to_mt_match AS
223-- Match Mainthread slice with the first GPU Completion that begins during it
224SELECT
225gcs.ts AS gcs_ts,
226gcs.ts_end AS gcs_ts_end,
227gcs.dur AS gcs_dur,
228gcs.idx AS idx,
229mtf.ts AS mts_ts,
230mtf.vsync AS vsync
231FROM android_sysui_cuj_surfaceflinger_gpu_completion_slices_in_cuj gcs
232-- join with all previous render frames but take latest start time
233JOIN android_sysui_cuj_surfaceflinger_main_thread_frames mtf ON gcs.ts > mtf.ts AND gcs.ts < mtf.ts + mtf.dur
234GROUP BY gcs.ts, gcs.ts_end, gcs.dur, gcs.idx;
235
236-- Those SurfaceFlinger Frames where we missed the deadline
237-- To avoid overlap - which could result in counting janky slices more than once - we limit the
238-- definition of each frame to:
239--  * beginning when the shared timeline actual frame starts, or - if later -
240--    when the previous main thread computation ended
241--  * ending when the next main thread computation begins, but no later than the
242--    shared timeline actual frame ends
243DROP TABLE IF EXISTS android_sysui_cuj_sf_missed_frames;
244CREATE TABLE android_sysui_cuj_sf_missed_frames AS
245SELECT
246  CAST(frame.name AS integer) AS frame_number,
247  CAST(frame.name AS integer) AS vsync,
248  max(mtf.ts_prev_frame_end, frame.ts) AS ts,
249  min(mtf.ts_next_frame_start, frame.ts_end) AS ts_end,
250  min(mtf.ts_next_frame_start, frame.ts_end) - max(mtf.ts_prev_frame_end, frame.ts) AS dur,
251  -- Needed for compatibility with downstream scripts
252  CAST(min(mtf.ts_next_frame_start, frame.ts_end) - max(mtf.ts_prev_frame_end, frame.ts) AS INTEGER) AS dur_frame,
253  gcs.gcs_ts,
254  gcs.gcs_ts_end,
255  gcs.gcs_dur,
256  CAST(1 AS INTEGER) AS app_missed
257FROM android_sysui_cuj_sf_actual_frame_timeline_slice frame
258JOIN android_sysui_cuj_surfaceflinger_main_thread_frames mtf ON frame.name = mtf.vsync
259JOIN android_sysui_cuj_gcs_to_mt_match gcs ON gcs.vsync = frame.name
260WHERE frame.jank_type != 'None';
261