aboutsummaryrefslogtreecommitdiff
path: root/src/trace_processor/metrics/chrome/scroll_flow_event.sql
blob: 05699f4cefa89a2e9476026a14ab5c3e604c47df (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
--
-- Copyright 2020 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.
--
-- While handling a InputLatency::GestureScrollUpdate event a sequence of Flows
-- define the critical path from Beginning to End. This metric breaks down the
-- flows for the same InputLatency::GestureScrollUpdate event.
--
-- WARNING: This metric should not be used as a source of truth. It is under
--          active development and the values & meaning might change without
--          notice.

-- Provides the scroll_jank table which gives us all the GestureScrollUpdate
-- events we care about and labels them janky or not.
SELECT RUN_METRIC('chrome/scroll_jank.sql');

-- We get all latency_info that have valid trace_ids, And we make a synthetic
-- one for the beginning of each GestureScrollUpdate event so we can track the
-- time between receiving the input and being converted into a scroll.
--
-- flows with a trace_id of -1 are incomplete and are difficult to reason about
-- (especially if GestureScrollUpdate flows end up getting -1). so ignore them
-- for this table.
DROP VIEW IF EXISTS latency_info_flow_step_and_ancestors;
CREATE VIEW latency_info_flow_step_and_ancestors AS
  SELECT
    *
  FROM (
    SELECT
      slice.name,
      slice.id,
      slice.ts,
      slice.dur,
      slice.track_id,
      EXTRACT_ARG(slice.arg_set_id, 'chrome_latency_info.trace_id') AS trace_id,
      EXTRACT_ARG(slice.arg_set_id, 'chrome_latency_info.step') AS step,
      COALESCE(ancestor_zero.name, slice.name) AS ancestor_name_zero,
      COALESCE(ancestor_zero.id, slice.id) AS ancestor_id_zero,
      COALESCE(ancestor_zero.ts, slice.ts) AS ancestor_ts_zero,
      COALESCE(ancestor_zero.dur, slice.dur) AS ancestor_dur_zero,
      COALESCE(ancestor_one.name, slice.name) AS ancestor_name_one,
      COALESCE(ancestor_one.id, slice.id) AS ancestor_id_one,
      COALESCE(ancestor_one.ts, slice.ts) AS ancestor_ts_one,
      COALESCE(ancestor_one.dur, slice.dur) AS ancestor_dur_one
    FROM
      slice LEFT JOIN
      ancestor_slice(slice.id) AS ancestor_zero
          ON ancestor_zero.depth = 0 LEFT JOIN
      ancestor_slice(slice.id) AS ancestor_one ON ancestor_one.depth = 1
    WHERE
      slice.name = 'LatencyInfo.Flow' AND
      EXTRACT_ARG(slice.arg_set_id, 'chrome_latency_info.trace_id') != -1
  ) flow JOIN (
      SELECT
        id AS scroll_slice_id,
        ts AS scroll_ts,
        dur AS scroll_dur,
        track_id AS scroll_track_id,
        trace_id AS scroll_trace_id,
        jank,
        gesture_scroll_id
      FROM scroll_jank
  ) scroll ON
    flow.trace_id = scroll.scroll_trace_id
  UNION ALL
  SELECT
    'InputLatency::GestureScrollUpdate' AS name,
    id,
    ts,
    dur,
    track_id,
    trace_id,
    'AsyncBegin' AS step,
    'InputLatency::GestureScrollUpdate' AS ancestor_name_zero,
    id AS ancestor_id_zero,
    ts AS ancestor_ts_zero,
    0 AS ancestor_dur_zero,
    'InputLatency::GestureScrollUpdate' AS ancestor_name_one,
    id AS ancestor_id_one,
    ts AS ancestor_ts_one,
    0 AS ancestor_dur_one,
    id AS scroll_slice_id,
    ts AS scroll_ts,
    dur AS scroll_dur,
    track_id AS scroll_track_id,
    trace_id AS scroll_trace_id,
    jank,
    gesture_scroll_id
  FROM scroll_jank
  ORDER BY gesture_scroll_id ASC, trace_id ASC, ts ASC;

-- See b/184134310, but "ThreadController active" spans multiple tasks and when
-- the top level parent is this event we should use the second event instead.
DROP VIEW IF EXISTS latency_info_flow_step;
CREATE VIEW latency_info_flow_step AS
  SELECT
    *,
    CASE WHEN ancestor_name_zero != "ThreadController active" THEN
      ancestor_name_zero ELSE ancestor_name_one END AS ancestor_name,
    CASE WHEN ancestor_name_zero != "ThreadController active" THEN
      ancestor_id_zero ELSE ancestor_id_one END AS ancestor_id,
    CASE WHEN ancestor_name_zero != "ThreadController active" THEN
      ancestor_ts_zero ELSE ancestor_ts_one END AS ancestor_ts,
    CASE WHEN ancestor_name_zero != "ThreadController active" THEN
      ancestor_dur_zero ELSE ancestor_dur_one END AS ancestor_dur
  FROM latency_info_flow_step_and_ancestors;

-- This is a heuristic to figure out which flow event properly joins this
-- GestureScrollUpdate. This heuristic is only needed in traces before we added
-- gesture_scroll_id.
--
-- We select the first |ts| from a flow event after its corresponding
-- GestureScrollUpdate has ended. This allows us to use this |ts| to contain all
-- flow events from the start of a particular scroll_slice_id (the slice id of
-- the async event) to that |ts|.
--
-- The reason for this is if these flow events share the same trace_id which can
-- occur if multiple chrome browsers are in the trace (webview & chrome for
-- example). We would normally add flow events from different scrolls, but by
-- limiting by the GestureScrollUpdate end we can prevent incorrect duplication.
-- This breaks of course if the same trace_id happens at the exact same time in
-- both browsers but this is hopefully unlikely.
DROP VIEW IF EXISTS max_latency_info_ts_per_trace_id;
CREATE VIEW max_latency_info_ts_per_trace_id AS
  SELECT
    scroll_slice_id,
    MIN(ts) AS max_flow_ts
  FROM latency_info_flow_step
  WHERE
    trace_id = scroll_trace_id AND
    ts > scroll_ts + scroll_dur
  GROUP BY scroll_slice_id;

-- As described by the comments about this uses the heuristic to remove any flow
-- events that aren't contained within the |max_flow_ts| and the beginning of
-- the GestureScrollUpdate. This prevents other processes that share the same
-- trace_id from inserting events in the middle.
--
-- Note: Must be a TABLE because it uses a window function which can behave
--       strangely in views.
DROP TABLE IF EXISTS latency_info_flow_step_filtered;
CREATE TABLE latency_info_flow_step_filtered AS
  SELECT
    ROW_NUMBER() OVER (ORDER BY
      flow.gesture_scroll_id ASC, trace_id ASC, ts ASC) AS row_number,
    *
  FROM
    latency_info_flow_step flow JOIN
    max_latency_info_ts_per_trace_id max_flow on
    max_flow.scroll_slice_id = flow.scroll_slice_id
  WHERE
    ts >= scroll_ts AND
    ts <= max_flow_ts
  ORDER BY flow.gesture_scroll_id ASC, flow.trace_id ASC, flow.ts ASC;

-- Take all the LatencyInfo.Flow events and within a |trace_id| join it with the
-- previous and nextflows. Some events are 'Unknown' when they don't have a step
-- but occur in the middle of the critical path. Most of these are errors though
-- and we've weeded I think all of them out (citation needed).
--
-- Note: Must be a TABLE because it uses a window function which can behave
--       strangely in views.
DROP TABLE IF EXISTS latency_info_flow_null_step_removed;
CREATE TABLE latency_info_flow_null_step_removed AS
  SELECT
    ROW_NUMBER() OVER (ORDER BY
      curr.gesture_scroll_id ASC, curr.trace_id ASC, curr.ts ASC
    ) AS row_number,
    curr.id,
    curr.ts,
    curr.dur,
    curr.track_id,
    curr.trace_id,
    curr.gesture_scroll_id,
    curr.scroll_slice_id,
    curr.scroll_ts,
    curr.scroll_dur,
    curr.scroll_track_id,
    curr.jank,
    curr.ancestor_id,
    curr.ancestor_ts,
    curr.ancestor_dur,
    curr.ancestor_ts + curr.ancestor_dur AS ancestor_end,
    CASE WHEN curr.step IS NULL THEN
      CASE WHEN
          prev.gesture_scroll_id != curr.gesture_scroll_id OR
          prev.trace_id != curr.trace_id OR
          prev.trace_id IS NULL OR
          prev.step = 'AsyncBegin' THEN
        'Begin'
      ELSE
        CASE WHEN
            next.gesture_scroll_id != curr.gesture_scroll_id OR
            next.trace_id != curr.trace_id OR
            next.trace_id IS NULL THEN
          'End'
        ELSE
         'Unknown'
        END
      END
    ELSE curr.step END AS step
  FROM
    latency_info_flow_step_filtered curr LEFT JOIN
    latency_info_flow_step_filtered prev ON
      curr.row_number - 1 = prev.row_number LEFT JOIN
    latency_info_flow_step_filtered next ON
      curr.row_number + 1 = next.row_number
  ORDER BY curr.gesture_scroll_id ASC, curr.trace_id ASC, curr.ts ASC;

-- Now that we've got the steps all named properly we want to join them with the
-- next step so we can compute the difference between the end of the current
-- step and the beginning of the next step.
DROP VIEW IF EXISTS scroll_flow_event;
CREATE VIEW scroll_flow_event AS
  SELECT
    curr.trace_id,
    curr.id,
    curr.ts,
    curr.dur,
    curr.track_id,
    curr.gesture_scroll_id,
    curr.scroll_slice_id,
    curr.scroll_ts,
    curr.scroll_dur,
    curr.scroll_track_id,
    curr.jank,
    curr.step,
    curr.ancestor_id,
    curr.ancestor_ts,
    curr.ancestor_dur,
    curr.ancestor_end,
    next.id as next_id,
    next.ts AS next_ts,
    next.dur AS next_dur,
    next.track_id AS next_track_id,
    next.trace_id AS next_trace_id,
    next.step AS next_step,
    CASE WHEN next.trace_id = curr.trace_id THEN
      next.ancestor_ts
    ELSE
      NULL
    END AS maybe_next_ancestor_ts
  FROM
    latency_info_flow_null_step_removed curr LEFT JOIN
    latency_info_flow_null_step_removed next ON
    curr.row_number + 1 = next.row_number
  ORDER BY curr.gesture_scroll_id, curr.trace_id, curr.ts;