1-- Copyright 2023 The Chromium Authors 2-- Use of this source code is governed by a BSD-style license that can be 3-- found in the LICENSE file. 4 5-- Annotates a trace with Speedometer 2.1 related information. 6-- 7-- The scripts below analyse traces with the following tracing options 8-- enabled: 9-- 10-- - Chromium: 11-- "blink.user_timing". 12-- 13-- NOTE: A regular speedometer run (e.g. from the website) will generate the 14-- required events. No need to add any extra JS or anything. 15-- 16-- Noteworthy tables: 17-- speedometer_mark: List of marks (event slices) emitted by Speedometer. 18-- These are the points in time Speedometer makes a clock reading to 19-- compute intervals of time for the final score. 20-- speedometer_measure_slice: Augmented slices for Speedometer measurements. 21-- These are the intervals of time Speedometer uses to compute the final 22-- score. 23-- speedometer_iteration_slice: Slice that covers one Speedometer iteration 24-- and has the total_time and score for it. If you average all the scores 25-- over all iterations you get the final Speedometer score for the run. 26 27-- List of marks (event slices) emitted by Speedometer. 28-- These are the points in time Speedometer makes a clock reading to compute 29-- intervals of time for the final score. 30-- 31-- @column slice_id Slice this data refers to. 32-- @column iteration Speedometer iteration the mark belongs to. 33-- @column suite_name Suite name 34-- @column test_name Test name 35-- @column mark_type Type of mark (start, sync-end, async-end) 36CREATE PERFETTO VIEW _chrome_speedometer_mark 37AS 38WITH 39 speedometer_21_suite_name(suite_name) AS ( 40 VALUES 41 ('VanillaJS-TodoMVC'), 42 ('Vanilla-ES2015-TodoMVC'), 43 ('Vanilla-ES2015-Babel-Webpack-TodoMVC'), 44 ('React-TodoMVC'), 45 ('React-Redux-TodoMVC'), 46 ('EmberJS-TodoMVC'), 47 ('EmberJS-Debug-TodoMVC'), 48 ('BackboneJS-TodoMVC'), 49 ('AngularJS-TodoMVC'), 50 ('Angular2-TypeScript-TodoMVC'), 51 ('VueJS-TodoMVC'), 52 ('jQuery-TodoMVC'), 53 ('Preact-TodoMVC'), 54 ('Inferno-TodoMVC'), 55 ('Elm-TodoMVC'), 56 ('Flight-TodoMVC') 57 ), 58 speedometer_21_test_name(test_name) AS ( 59 VALUES 60 ('Adding100Items'), 61 ('CompletingAllItems'), 62 -- This seems to be an issue with Speedometer 2.1. All tests delete all items, 63 -- but for some reason the test names do not match for all suites. 64 ('DeletingAllItems'), 65 ('DeletingItems') 66 ), 67 speedometer_21_test_mark_type(mark_type) AS ( 68 VALUES 69 ('start'), 70 ('sync-end'), 71 ('async-end') 72 ), 73 -- Make sure we only look at slices with names we expect. 74 speedometer_mark_name AS ( 75 SELECT 76 s.suite_name || '.' || t.test_name || '-' || m.mark_type AS name, 77 s.suite_name, 78 t.test_name, 79 m.mark_type 80 FROM 81 speedometer_21_suite_name AS s, 82 speedometer_21_test_name AS t, 83 speedometer_21_test_mark_type AS m 84 ) 85SELECT 86 s.id AS slice_id, 87 RANK() OVER (PARTITION BY name ORDER BY ts ASC) AS iteration, 88 m.suite_name, 89 m.test_name, 90 m.mark_type 91FROM slice AS s 92JOIN speedometer_mark_name AS m 93 USING (name) 94WHERE category = 'blink.user_timing'; 95 96-- Augmented slices for Speedometer measurements. 97-- These are the intervals of time Speedometer uses to compute the final score. 98-- There are two intervals that are measured for every test: sync and async 99-- sync is the time between the start and sync-end marks, async is the time 100-- between the sync-end and async-end marks. 101CREATE PERFETTO TABLE chrome_speedometer_measure( 102 -- Speedometer iteration the mark belongs to. 103 iteration INT, 104 -- Suite name 105 suite_name STRING, 106 -- Test name 107 test_name STRING, 108 -- Type of the measure (sync or async) 109 measure_type STRING, 110 -- Start timestamp of the measure 111 ts INT, 112 -- Duration of the measure 113 dur INT 114) 115AS 116WITH 117 -- Get the 3 test timestamps (start, sync-end, async-end) in one row. Using a 118 -- the LAG window function and partitioning by test. 2 out of the 3 rows 119 -- generated per test will have some NULL ts values. 120 augmented AS ( 121 SELECT 122 iteration, 123 suite_name, 124 test_name, 125 ts AS async_end_ts, 126 LAG(ts, 1) 127 OVER (PARTITION BY iteration, suite_name, test_name ORDER BY ts ASC) 128 AS sync_end_ts, 129 LAG(ts, 2) 130 OVER (PARTITION BY iteration, suite_name, test_name ORDER BY ts ASC) 131 AS start_ts, 132 COUNT() 133 OVER (PARTITION BY iteration, suite_name, test_name ORDER BY ts ASC) 134 AS mark_count 135 FROM _chrome_speedometer_mark 136 JOIN slice 137 USING (slice_id) 138 ), 139 filtered AS ( 140 SELECT * 141 FROM augmented 142 -- This server 2 purposes: make sure we have all the marks (think truncated 143 -- trace), and remove the NULL ts values due to the LAG window function. 144 WHERE mark_count = 3 145 ) 146SELECT 147 iteration, 148 suite_name, 149 test_name, 150 'async' AS measure_type, 151 sync_end_ts AS ts, 152 async_end_ts - sync_end_ts AS dur 153FROM filtered 154UNION ALL 155SELECT 156 iteration, 157 suite_name, 158 test_name, 159 'sync' AS measure_type, 160 start_ts AS ts, 161 sync_end_ts - start_ts AS dur 162FROM filtered; 163 164-- Slice that covers one Speedometer iteration. 165-- This slice is actually estimated as a default Speedometer run will not emit 166-- marks to cover this interval. The metrics associated are the same ones 167-- Speedometer would output, but note we use ns precision (Speedometer uses 168-- ~100us) so the actual values might differ a bit. Also note Speedometer 169-- returns the values in ms these here and in ns. 170CREATE PERFETTO TABLE chrome_speedometer_iteration( 171 -- Speedometer iteration. 172 iteration INT, 173 -- Start timestamp of the iteration 174 ts INT, 175 -- Duration of the iteration 176 dur INT, 177 -- Total duration of the measures in this iteration 178 total INT, 179 -- Average suite duration for this iteration. 180 mean INT, 181 -- Geometric mean of the suite durations for this iteration. 182 geomean INT, 183 -- Speedometer score for this iteration (The total score for a run in the average of all iteration scores). 184 score INT 185) AS 186SELECT 187 iteration, 188 MIN(start) AS ts, 189 MAX(end) - MIN(start) AS dur, 190 SUM(suite_total) AS total, 191 AVG(suite_total)AS mean, 192 -- Compute geometric mean using LN instead of multiplication to prevent 193 -- overflows 194 EXP(AVG(LN(suite_total))) AS geomean, 195 1e9 / EXP(AVG(LN(suite_total))) * 60 / 3 AS score 196FROM 197 ( 198 SELECT 199 iteration, SUM(dur) AS suite_total, MIN(ts) AS start, MAX(ts + dur) AS end 200 FROM chrome_speedometer_measure 201 GROUP BY suite_name, iteration 202 ) 203GROUP BY iteration; 204