1-- 2-- Copyright 2021 The Android Open Source Project 3-- 4-- Licensed under the Apache License, Version 2.0 (the 'License'); 5-- you may not use this file except in compliance with the License. 6-- You may obtain a copy of the License at 7-- 8-- https://www.apache.org/licenses/LICENSE-2.0 9-- 10-- Unless required by applicable law or agreed to in writing, software 11-- distributed under the License is distributed on an 'AS IS' BASIS, 12-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13-- See the License for the specific language governing permissions and 14-- limitations under the License. 15-- 16-- While handling a InputLatency::{{gesture_update}} event a sequence of Flows 17-- define the critical path from Beginning to End. This metric breaks down the 18-- flows for the same InputLatency::{{gesture_update}} event. 19-- 20-- WARNING: This metric should not be used as a source of truth. It is under 21-- active development and the values & meaning might change without 22-- notice. 23 24-- Provides the {{prefix}}_jank table which gives us all the {{gesture_update}} 25-- events we care about and labels them janky or not. 26SELECT RUN_METRIC('chrome/{{prefix}}_jank.sql'); 27 28-- We get all latency_info that have valid trace_ids, And we make a synthetic 29-- one for the beginning of each {{gesture_update}} event so we can track the 30-- time between receiving the input and being converted into a gesture. 31-- 32-- flows with a trace_id of -1 are incomplete and are difficult to reason about 33-- (especially if {{gesture_update}} flows end up getting -1). so ignore them 34-- for this table. 35DROP VIEW IF EXISTS {{prefix}}_latency_info_flow_step_and_ancestors; 36CREATE VIEW {{prefix}}_latency_info_flow_step_and_ancestors AS 37SELECT 38 * 39FROM ( 40 SELECT 41 slice.name, 42 slice.id, 43 slice.ts, 44 slice.dur, 45 slice.track_id, 46 EXTRACT_ARG(slice.arg_set_id, 'chrome_latency_info.trace_id') AS trace_id, 47 EXTRACT_ARG(slice.arg_set_id, 'chrome_latency_info.step') AS step, 48 COALESCE(ancestor_zero.name, slice.name) AS ancestor_name_zero, 49 COALESCE(ancestor_zero.id, slice.id) AS ancestor_id_zero, 50 COALESCE(ancestor_zero.ts, slice.ts) AS ancestor_ts_zero, 51 COALESCE(ancestor_zero.dur, slice.dur) AS ancestor_dur_zero, 52 COALESCE(ancestor_one.name, slice.name) AS ancestor_name_one, 53 COALESCE(ancestor_one.id, slice.id) AS ancestor_id_one, 54 COALESCE(ancestor_one.ts, slice.ts) AS ancestor_ts_one, 55 COALESCE(ancestor_one.dur, slice.dur) AS ancestor_dur_one 56 FROM 57 slice LEFT JOIN 58 ancestor_slice(slice.id) AS ancestor_zero 59 ON ancestor_zero.depth = 0 LEFT JOIN 60 ancestor_slice(slice.id) AS ancestor_one ON ancestor_one.depth = 1 61 WHERE 62 slice.name = 'LatencyInfo.Flow' 63 AND EXTRACT_ARG(slice.arg_set_id, 'chrome_latency_info.trace_id') != -1 64 ) flow JOIN ( 65 SELECT 66 id AS gesture_slice_id, 67 ts AS gesture_ts, 68 dur AS {{prefix}}_dur, 69 track_id AS gesture_track_id, 70 trace_id AS {{prefix}}_trace_id, 71 jank, 72 {{id_field}}, 73 avg_vsync_interval 74 FROM {{prefix}}_jank 75 ) gesture ON 76 flow.trace_id = gesture.{{prefix}}_trace_id 77UNION ALL 78SELECT 79 'InputLatency::{{gesture_update}}' AS name, 80 id, 81 ts, 82 dur, 83 track_id, 84 trace_id, 85 'AsyncBegin' AS step, 86 'InputLatency::{{gesture_update}}' AS ancestor_name_zero, 87 id AS ancestor_id_zero, 88 ts AS ancestor_ts_zero, 89 0 AS ancestor_dur_zero, 90 'InputLatency::{{gesture_update}}' AS ancestor_name_one, 91 id AS ancestor_id_one, 92 ts AS ancestor_ts_one, 93 0 AS ancestor_dur_one, 94 id AS gesture_slice_id, 95 ts AS gesture_ts, 96 dur AS {{prefix}}_dur, 97 track_id AS gesture_track_id, 98 trace_id AS {{prefix}}_trace_id, 99 jank, 100 {{id_field}}, 101 avg_vsync_interval 102FROM {{prefix}}_jank 103ORDER BY {{id_field}} ASC, trace_id ASC, ts ASC; 104 105-- See b/184134310, but "ThreadController active" spans multiple tasks and when 106-- the top level parent is this event we should use the second event instead. 107DROP VIEW IF EXISTS {{prefix}}_latency_info_flow_step; 108CREATE VIEW {{prefix}}_latency_info_flow_step AS 109SELECT 110 *, 111 CASE WHEN ancestor_name_zero != "ThreadController active" THEN 112 ancestor_name_zero ELSE ancestor_name_one END AS ancestor_name, 113 CASE WHEN ancestor_name_zero != "ThreadController active" THEN 114 ancestor_id_zero ELSE ancestor_id_one END AS ancestor_id, 115 CASE WHEN ancestor_name_zero != "ThreadController active" THEN 116 ancestor_ts_zero ELSE ancestor_ts_one END AS ancestor_ts, 117 CASE WHEN ancestor_name_zero != "ThreadController active" THEN 118 ancestor_dur_zero ELSE ancestor_dur_one END AS ancestor_dur 119FROM {{prefix}}_latency_info_flow_step_and_ancestors; 120 121-- This is a heuristic to figure out which flow event properly joins this 122-- {{gesture_update}}. This heuristic is only needed in traces before we added 123-- {{id_field}}. 124-- 125-- We select the first |ts| from a flow event after its corresponding 126-- {{gesture_update}} has ended. This allows us to use this |ts| to contain all 127-- flow events from the start of a particular gesture_slice_id (the slice id of 128-- the async event) to that |ts|. 129-- 130-- The reason for this is if these flow events share the same trace_id which can 131-- occur if multiple chrome browsers are in the trace (webview & chrome for 132-- example). We would normally add flow events from different gestures, but by 133-- limiting by the {{gesture_update}} end we can prevent incorrect duplication. 134-- This breaks of course if the same trace_id happens at the exact same time in 135-- both browsers but this is hopefully unlikely. 136DROP VIEW IF EXISTS {{prefix}}_max_latency_info_ts_per_trace_id; 137CREATE VIEW {{prefix}}_max_latency_info_ts_per_trace_id AS 138SELECT 139 gesture_slice_id, 140 MIN(ts) AS max_flow_ts 141FROM {{prefix}}_latency_info_flow_step 142WHERE 143 trace_id = {{prefix}}_trace_id 144 AND ts > gesture_ts + {{prefix}}_dur 145GROUP BY gesture_slice_id; 146 147-- As described by the comments about this uses the heuristic to remove any flow 148-- events that aren't contained within the |max_flow_ts| and the beginning of 149-- the {{gesture_update}}. This prevents other processes that share the same 150-- trace_id from inserting events in the middle. 151-- 152-- Note: Must be a TABLE because it uses a window function which can behave 153-- strangely in views. 154DROP TABLE IF EXISTS {{prefix}}_latency_info_flow_step_filtered; 155CREATE TABLE {{prefix}}_latency_info_flow_step_filtered AS 156SELECT 157 ROW_NUMBER() OVER (ORDER BY 158 flow.{{id_field}} ASC, trace_id ASC, ts ASC) AS row_number, 159 * 160FROM 161 {{prefix}}_latency_info_flow_step flow JOIN 162 {{prefix}}_max_latency_info_ts_per_trace_id max_flow ON 163 max_flow.gesture_slice_id = flow.gesture_slice_id 164WHERE 165 ts >= gesture_ts 166 AND ts <= max_flow_ts 167ORDER BY flow.{{id_field}} ASC, flow.trace_id ASC, flow.ts ASC; 168 169-- Take all the LatencyInfo.Flow events and within a |trace_id| join it with the 170-- previous and nextflows. Some events are 'Unknown' when they don't have a step 171-- but occur in the middle of the critical path. Most of these are errors though 172-- and we've weeded I think all of them out (citation needed). 173-- 174-- Note: Must be a TABLE because it uses a window function which can behave 175-- strangely in views. 176DROP TABLE IF EXISTS {{prefix}}_latency_info_flow_null_step_removed; 177CREATE TABLE {{prefix}}_latency_info_flow_null_step_removed AS 178SELECT 179 ROW_NUMBER() OVER (ORDER BY 180 curr.{{id_field}} ASC, curr.trace_id ASC, curr.ts ASC 181 ) AS row_number, 182 curr.id, 183 curr.ts, 184 curr.dur, 185 curr.track_id, 186 curr.trace_id, 187 curr.{{id_field}}, 188 curr.avg_vsync_interval, 189 curr.gesture_slice_id, 190 curr.gesture_ts, 191 curr.{{prefix}}_dur, 192 curr.gesture_track_id, 193 curr.jank, 194 curr.ancestor_id, 195 curr.ancestor_ts, 196 curr.ancestor_dur, 197 curr.ancestor_ts + curr.ancestor_dur AS ancestor_end, 198 COALESCE( 199 curr.step, 200 CASE WHEN 201 prev.{{id_field}} != curr.{{id_field}} 202 OR prev.trace_id != curr.trace_id 203 OR prev.trace_id IS NULL 204 OR prev.step = 'AsyncBegin' THEN 205 'Begin' 206 ELSE 207 CASE WHEN 208 next.{{id_field}} != curr.{{id_field}} 209 OR next.trace_id != curr.trace_id 210 OR next.trace_id IS NULL THEN 211 'End' 212 ELSE 213 'Unknown' 214 END 215 END 216 ) AS step 217 FROM 218 {{prefix}}_latency_info_flow_step_filtered curr LEFT JOIN 219 {{prefix}}_latency_info_flow_step_filtered prev ON 220 curr.row_number - 1 = prev.row_number LEFT JOIN 221 {{prefix}}_latency_info_flow_step_filtered next ON 222 curr.row_number + 1 = next.row_number 223 ORDER BY curr.{{id_field}} ASC, curr.trace_id ASC, curr.ts ASC; 224 225-- Now that we've got the steps all named properly we want to join them with the 226-- next step so we can compute the difference between the end of the current 227-- step and the beginning of the next step. 228DROP VIEW IF EXISTS {{prefix}}_flow_event; 229CREATE VIEW {{prefix}}_flow_event AS 230SELECT 231 curr.trace_id, 232 curr.id, 233 curr.ts, 234 curr.dur, 235 curr.track_id, 236 curr.{{id_field}}, 237 curr.avg_vsync_interval, 238 curr.gesture_slice_id AS {{prefix}}_slice_id, 239 curr.gesture_ts AS {{prefix}}_ts, 240 curr.{{prefix}}_dur AS {{prefix}}_dur, 241 curr.gesture_track_id AS {{prefix}}_track_id, 242 curr.jank, 243 curr.step, 244 curr.ancestor_id, 245 curr.ancestor_ts, 246 curr.ancestor_dur, 247 curr.ancestor_end, 248 next.id AS next_id, 249 next.ts AS next_ts, 250 next.dur AS next_dur, 251 next.track_id AS next_track_id, 252 next.trace_id AS next_trace_id, 253 next.step AS next_step, 254 CASE WHEN next.trace_id = curr.trace_id THEN 255 next.ancestor_ts 256 ELSE 257 NULL 258 END AS maybe_next_ancestor_ts 259FROM 260 {{prefix}}_latency_info_flow_null_step_removed curr LEFT JOIN 261 {{prefix}}_latency_info_flow_null_step_removed next ON 262 curr.row_number + 1 = next.row_number 263ORDER BY curr.{{id_field}}, curr.trace_id, curr.ts; 264