-- Copyright 2023 The Chromium Authors -- Use of this source code is governed by a BSD-style license that can be -- found in the LICENSE file. -- Annotates a trace with Speedometer 2.1 related information. -- -- The scripts below analyse traces with the following tracing options -- enabled: -- -- - Chromium: -- "blink.user_timing". -- -- NOTE: A regular speedometer run (e.g. from the website) will generate the -- required events. No need to add any extra JS or anything. -- -- Noteworthy tables: -- speedometer_mark: List of marks (event slices) emitted by Speedometer. -- These are the points in time Speedometer makes a clock reading to -- compute intervals of time for the final score. -- speedometer_measure_slice: Augmented slices for Speedometer measurements. -- These are the intervals of time Speedometer uses to compute the final -- score. -- speedometer_iteration_slice: Slice that covers one Speedometer iteration -- and has the total_time and score for it. If you average all the scores -- over all iterations you get the final Speedometer score for the run. -- List of marks (event slices) emitted by Speedometer. -- These are the points in time Speedometer makes a clock reading to compute -- intervals of time for the final score. -- -- @column slice_id Slice this data refers to. -- @column iteration Speedometer iteration the mark belongs to. -- @column suite_name Suite name -- @column test_name Test name -- @column mark_type Type of mark (start, sync-end, async-end) CREATE PERFETTO VIEW _chrome_speedometer_mark AS WITH speedometer_21_suite_name(suite_name) AS ( VALUES ('VanillaJS-TodoMVC'), ('Vanilla-ES2015-TodoMVC'), ('Vanilla-ES2015-Babel-Webpack-TodoMVC'), ('React-TodoMVC'), ('React-Redux-TodoMVC'), ('EmberJS-TodoMVC'), ('EmberJS-Debug-TodoMVC'), ('BackboneJS-TodoMVC'), ('AngularJS-TodoMVC'), ('Angular2-TypeScript-TodoMVC'), ('VueJS-TodoMVC'), ('jQuery-TodoMVC'), ('Preact-TodoMVC'), ('Inferno-TodoMVC'), ('Elm-TodoMVC'), ('Flight-TodoMVC') ), speedometer_21_test_name(test_name) AS ( VALUES ('Adding100Items'), ('CompletingAllItems'), -- This seems to be an issue with Speedometer 2.1. All tests delete all items, -- but for some reason the test names do not match for all suites. ('DeletingAllItems'), ('DeletingItems') ), speedometer_21_test_mark_type(mark_type) AS ( VALUES ('start'), ('sync-end'), ('async-end') ), -- Make sure we only look at slices with names we expect. speedometer_mark_name AS ( SELECT s.suite_name || '.' || t.test_name || '-' || m.mark_type AS name, s.suite_name, t.test_name, m.mark_type FROM speedometer_21_suite_name AS s, speedometer_21_test_name AS t, speedometer_21_test_mark_type AS m ) SELECT s.id AS slice_id, RANK() OVER (PARTITION BY name ORDER BY ts ASC) AS iteration, m.suite_name, m.test_name, m.mark_type FROM slice AS s JOIN speedometer_mark_name AS m USING (name) WHERE category = 'blink.user_timing'; -- Augmented slices for Speedometer measurements. -- These are the intervals of time Speedometer uses to compute the final score. -- There are two intervals that are measured for every test: sync and async -- sync is the time between the start and sync-end marks, async is the time -- between the sync-end and async-end marks. CREATE PERFETTO TABLE chrome_speedometer_measure( -- Speedometer iteration the mark belongs to. iteration INT, -- Suite name suite_name STRING, -- Test name test_name STRING, -- Type of the measure (sync or async) measure_type STRING, -- Start timestamp of the measure ts INT, -- Duration of the measure dur INT ) AS WITH -- Get the 3 test timestamps (start, sync-end, async-end) in one row. Using a -- the LAG window function and partitioning by test. 2 out of the 3 rows -- generated per test will have some NULL ts values. augmented AS ( SELECT iteration, suite_name, test_name, ts AS async_end_ts, LAG(ts, 1) OVER (PARTITION BY iteration, suite_name, test_name ORDER BY ts ASC) AS sync_end_ts, LAG(ts, 2) OVER (PARTITION BY iteration, suite_name, test_name ORDER BY ts ASC) AS start_ts, COUNT() OVER (PARTITION BY iteration, suite_name, test_name ORDER BY ts ASC) AS mark_count FROM _chrome_speedometer_mark JOIN slice USING (slice_id) ), filtered AS ( SELECT * FROM augmented -- This server 2 purposes: make sure we have all the marks (think truncated -- trace), and remove the NULL ts values due to the LAG window function. WHERE mark_count = 3 ) SELECT iteration, suite_name, test_name, 'async' AS measure_type, sync_end_ts AS ts, async_end_ts - sync_end_ts AS dur FROM filtered UNION ALL SELECT iteration, suite_name, test_name, 'sync' AS measure_type, start_ts AS ts, sync_end_ts - start_ts AS dur FROM filtered; -- Slice that covers one Speedometer iteration. -- This slice is actually estimated as a default Speedometer run will not emit -- marks to cover this interval. The metrics associated are the same ones -- Speedometer would output, but note we use ns precision (Speedometer uses -- ~100us) so the actual values might differ a bit. Also note Speedometer -- returns the values in ms these here and in ns. CREATE PERFETTO TABLE chrome_speedometer_iteration( -- Speedometer iteration. iteration INT, -- Start timestamp of the iteration ts INT, -- Duration of the iteration dur INT, -- Total duration of the measures in this iteration total INT, -- Average suite duration for this iteration. mean INT, -- Geometric mean of the suite durations for this iteration. geomean INT, -- Speedometer score for this iteration (The total score for a run in the average of all iteration scores). score INT ) AS SELECT iteration, MIN(start) AS ts, MAX(end) - MIN(start) AS dur, SUM(suite_total) AS total, AVG(suite_total)AS mean, -- Compute geometric mean using LN instead of multiplication to prevent -- overflows EXP(AVG(LN(suite_total))) AS geomean, 1e9 / EXP(AVG(LN(suite_total))) * 60 / 3 AS score FROM ( SELECT iteration, SUM(dur) AS suite_total, MIN(ts) AS start, MAX(ts + dur) AS end FROM chrome_speedometer_measure GROUP BY suite_name, iteration ) GROUP BY iteration;