aboutsummaryrefslogtreecommitdiff
path: root/src/trace_processor/metrics/sql/chrome/gesture_flow_event.sql
blob: 69b824d7437e1ef069358fac9883d682da3faf74 (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
259
260
261
262
--
-- Copyright 2021 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::{{gesture_update}} event a sequence of Flows
-- define the critical path from Beginning to End. This metric breaks down the
-- flows for the same InputLatency::{{gesture_update}} 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 {{prefix}}_jank table which gives us all the {{gesture_update}}
-- events we care about and labels them janky or not.
SELECT RUN_METRIC('chrome/{{prefix}}_jank.sql');

-- We get all latency_info that have valid trace_ids, And we make a synthetic
-- one for the beginning of each {{gesture_update}} event so we can track the
-- time between receiving the input and being converted into a gesture.
--
-- flows with a trace_id of -1 are incomplete and are difficult to reason about
-- (especially if {{gesture_update}} flows end up getting -1). so ignore them
-- for this table.
DROP VIEW IF EXISTS {{prefix}}_latency_info_flow_step_and_ancestors;
CREATE VIEW {{prefix}}_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 gesture_slice_id,
        ts AS gesture_ts,
        dur AS {{prefix}}_dur,
        track_id AS gesture_track_id,
        trace_id AS {{prefix}}_trace_id,
        jank,
        {{id_field}},
        avg_vsync_interval
      FROM {{prefix}}_jank
  ) gesture ON
    flow.trace_id = gesture.{{prefix}}_trace_id
  UNION ALL
  SELECT
    'InputLatency::{{gesture_update}}' AS name,
    id,
    ts,
    dur,
    track_id,
    trace_id,
    'AsyncBegin' AS step,
    'InputLatency::{{gesture_update}}' AS ancestor_name_zero,
    id AS ancestor_id_zero,
    ts AS ancestor_ts_zero,
    0 AS ancestor_dur_zero,
    'InputLatency::{{gesture_update}}' AS ancestor_name_one,
    id AS ancestor_id_one,
    ts AS ancestor_ts_one,
    0 AS ancestor_dur_one,
    id AS gesture_slice_id,
    ts AS gesture_ts,
    dur AS {{prefix}}_dur,
    track_id AS gesture_track_id,
    trace_id AS {{prefix}}_trace_id,
    jank,
    {{id_field}},
    avg_vsync_interval
  FROM {{prefix}}_jank
  ORDER BY {{id_field}} 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 {{prefix}}_latency_info_flow_step;
CREATE VIEW {{prefix}}_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 {{prefix}}_latency_info_flow_step_and_ancestors;

-- This is a heuristic to figure out which flow event properly joins this
-- {{gesture_update}}. This heuristic is only needed in traces before we added
-- {{id_field}}.
--
-- We select the first |ts| from a flow event after its corresponding
-- {{gesture_update}} has ended. This allows us to use this |ts| to contain all
-- flow events from the start of a particular gesture_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 gestures, but by
-- limiting by the {{gesture_update}} 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 {{prefix}}_max_latency_info_ts_per_trace_id;
CREATE VIEW {{prefix}}_max_latency_info_ts_per_trace_id AS
  SELECT
    gesture_slice_id,
    MIN(ts) AS max_flow_ts
  FROM {{prefix}}_latency_info_flow_step
  WHERE
    trace_id = {{prefix}}_trace_id AND
    ts > gesture_ts + {{prefix}}_dur
  GROUP BY gesture_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 {{gesture_update}}. 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 {{prefix}}_latency_info_flow_step_filtered;
CREATE TABLE {{prefix}}_latency_info_flow_step_filtered AS
  SELECT
    ROW_NUMBER() OVER (ORDER BY
      flow.{{id_field}} ASC, trace_id ASC, ts ASC) AS row_number,
    *
  FROM
    {{prefix}}_latency_info_flow_step flow JOIN
    {{prefix}}_max_latency_info_ts_per_trace_id max_flow on
    max_flow.gesture_slice_id = flow.gesture_slice_id
  WHERE
    ts >= gesture_ts AND
    ts <= max_flow_ts
  ORDER BY flow.{{id_field}} 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 {{prefix}}_latency_info_flow_null_step_removed;
CREATE TABLE {{prefix}}_latency_info_flow_null_step_removed AS
  SELECT
    ROW_NUMBER() OVER (ORDER BY
      curr.{{id_field}} ASC, curr.trace_id ASC, curr.ts ASC
    ) AS row_number,
    curr.id,
    curr.ts,
    curr.dur,
    curr.track_id,
    curr.trace_id,
    curr.{{id_field}},
    curr.avg_vsync_interval,
    curr.gesture_slice_id,
    curr.gesture_ts,
    curr.{{prefix}}_dur,
    curr.gesture_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.{{id_field}} != curr.{{id_field}} OR
          prev.trace_id != curr.trace_id OR
          prev.trace_id IS NULL OR
          prev.step = 'AsyncBegin' THEN
        'Begin'
      ELSE
        CASE WHEN
            next.{{id_field}} != curr.{{id_field}} 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
    {{prefix}}_latency_info_flow_step_filtered curr LEFT JOIN
    {{prefix}}_latency_info_flow_step_filtered prev ON
      curr.row_number - 1 = prev.row_number LEFT JOIN
    {{prefix}}_latency_info_flow_step_filtered next ON
      curr.row_number + 1 = next.row_number
  ORDER BY curr.{{id_field}} 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 {{prefix}}_flow_event;
CREATE VIEW {{prefix}}_flow_event AS
  SELECT
    curr.trace_id,
    curr.id,
    curr.ts,
    curr.dur,
    curr.track_id,
    curr.{{id_field}},
    curr.avg_vsync_interval,
    curr.gesture_slice_id AS {{prefix}}_slice_id,
    curr.gesture_ts AS {{prefix}}_ts,
    curr.{{prefix}}_dur AS {{prefix}}_dur,
    curr.gesture_track_id AS {{prefix}}_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
    {{prefix}}_latency_info_flow_null_step_removed curr LEFT JOIN
    {{prefix}}_latency_info_flow_null_step_removed next ON
    curr.row_number + 1 = next.row_number
  ORDER BY curr.{{id_field}}, curr.trace_id, curr.ts;