• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
16SELECT RUN_METRIC('chrome/chrome_processes.sql');
17
18-- Helper for thread slices
19DROP VIEW IF EXISTS thread_slice;
20CREATE VIEW thread_slice AS
21SELECT s.*, thread.utid, thread.upid
22FROM slice s
23INNER JOIN thread_track ON s.track_id = thread_track.id
24INNER JOIN thread USING(utid);
25
26--------------------------------------------------------------------------------
27-- Find all playbacks on renderer main threads.
28
29DROP VIEW IF EXISTS PlaybackStart;
30CREATE VIEW PlaybackStart AS
31SELECT
32  EXTRACT_ARG(s.arg_set_id, 'debug.id') AS playback_id,
33  s.ts AS playback_start,
34  upid
35FROM slice s
36INNER JOIN thread_track ON s.track_id = thread_track.id
37INNER JOIN thread USING(utid)
38WHERE
39  s.name = 'WebMediaPlayerImpl::DoLoad'
40  AND thread.name = 'CrRendererMain';
41
42--------------------------------------------------------------------------------
43-- Find the first video render time after the playback to compute
44-- time_to_video_play.
45
46DROP VIEW IF EXISTS VideoStart;
47CREATE VIEW VideoStart AS
48SELECT
49  playback_id,
50  playback_start,
51  PlaybackStart.upid,
52  MIN(s.ts) AS video_start
53FROM PlaybackStart, thread_slice s
54WHERE
55  s.name = 'VideoRendererImpl::Render'
56  AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = playback_id
57  AND s.upid = PlaybackStart.upid
58GROUP BY playback_id, playback_start, PlaybackStart.upid;
59
60--------------------------------------------------------------------------------
61-- Find the first audio render time after the playback to compute
62-- time_to_audio_play.
63
64DROP VIEW IF EXISTS AudioStart;
65CREATE VIEW AudioStart AS
66SELECT
67  playback_id,
68  playback_start,
69  PlaybackStart.upid,
70  MIN(s.ts) AS audio_start
71FROM PlaybackStart, thread_slice s
72WHERE
73  s.name = 'AudioRendererImpl::Render'
74  AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = playback_id
75  AND s.upid = PlaybackStart.upid
76GROUP BY playback_id, playback_start, PlaybackStart.upid;
77
78--------------------------------------------------------------------------------
79-- Sum up the dropped frame count from all such events for each playback to
80-- compute dropped_frame_count.
81
82DROP VIEW IF EXISTS DroppedFrameCount;
83CREATE VIEW DroppedFrameCount AS
84SELECT
85  playback_id,
86  vs.upid,
87  SUM(
88    CASE
89    WHEN s.arg_set_id IS NULL THEN 0
90    ELSE EXTRACT_ARG(s.arg_set_id, 'debug.count') END
91  ) AS dropped_frame_count
92FROM VideoStart vs
93LEFT JOIN thread_slice s ON
94  s.name = 'VideoFramesDropped'
95  AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = playback_id
96  AND s.upid = vs.upid
97GROUP BY playback_id, vs.upid;
98
99--------------------------------------------------------------------------------
100-- Compute seek times.
101
102-- Find the seeks.
103DROP VIEW IF EXISTS SeekStart;
104CREATE VIEW SeekStart AS
105SELECT
106  playback_id,
107  PlaybackStart.upid,
108  s.ts AS seek_start,
109  EXTRACT_ARG(s.arg_set_id, 'debug.target') AS seek_target
110FROM PlaybackStart
111LEFT JOIN thread_slice s
112WHERE
113  s.name = 'WebMediaPlayerImpl::DoSeek'
114  AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = playback_id
115  AND s.upid = PlaybackStart.upid;
116
117-- Partition by the next seek's ts, so that we can filter for events occurring
118-- within each seek's window below.
119DROP VIEW IF EXISTS SeekPartitioned;
120CREATE VIEW SeekPartitioned AS
121SELECT
122  *,
123  LEAD(seek_start) OVER (
124    PARTITION BY playback_id, upid
125    ORDER BY seek_start ASC
126  ) AS seek_end
127FROM SeekStart;
128
129-- Find the subsequent matching pipeline seeks that occur before the next seek.
130DROP VIEW IF EXISTS PipelineSeek;
131CREATE VIEW PipelineSeek AS
132SELECT
133  seek.*,
134  (
135    SELECT MIN(s.ts)
136    FROM thread_slice s
137    WHERE
138      s.name = 'WebMediaPlayerImpl::OnPipelineSeeked'
139      AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = seek.playback_id
140      AND EXTRACT_ARG(s.arg_set_id, 'debug.target') = seek.seek_target
141      AND s.upid = seek.upid
142      AND s.ts >= seek.seek_start
143      AND (seek.seek_end IS NULL OR s.ts < seek.seek_end)
144  ) AS pipeline_seek
145FROM SeekPartitioned seek;
146
147-- Find the subsequent buffering events that occur before the next seek.
148DROP VIEW IF EXISTS SeekComplete;
149CREATE VIEW SeekComplete AS
150SELECT
151  seek.*,
152  (
153    SELECT MIN(s.ts)
154    FROM thread_slice s
155    WHERE
156      s.name = 'WebMediaPlayerImpl::BufferingHaveEnough'
157      AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = seek.playback_id
158      AND s.upid = seek.upid
159      AND s.ts >= seek.pipeline_seek
160      AND (seek.seek_end IS NULL OR s.ts < seek.seek_end)
161  ) AS seek_complete
162FROM PipelineSeek seek;
163
164-- Find the subsequent buffering events that occur before the next seek.
165DROP VIEW IF EXISTS ValidSeek;
166CREATE VIEW ValidSeek AS
167SELECT
168  s.*
169FROM SeekComplete s
170WHERE
171  s.pipeline_seek IS NOT NULL
172  AND s.seek_complete IS NOT NULL;
173
174--------------------------------------------------------------------------------
175-- Find playback end timestamps and their duration for playbacks without seeks
176-- to compute buffering_time.
177
178-- Helper view that shows either video or audio start for each playback
179DROP VIEW IF EXISTS AVStart;
180CREATE VIEW AVStart AS
181SELECT
182  v.playback_id,
183  v.playback_start,
184  v.upid,
185  v.video_start AS av_start
186FROM VideoStart v
187UNION
188SELECT
189  a.playback_id,
190  a.playback_start,
191  a.upid,
192  a.audio_start AS av_start
193FROM AudioStart a
194WHERE a.playback_id NOT IN (SELECT playback_id FROM VideoStart);
195
196-- Find the corresponding media end events and their reported duration.
197DROP VIEW IF EXISTS PlaybackEnd;
198CREATE VIEW PlaybackEnd AS
199SELECT
200  AVStart.*,
201  slice.ts AS playback_end,
202  EXTRACT_ARG(slice.arg_set_id, 'debug.duration') * 1e9 AS duration
203FROM AVStart
204INNER JOIN slice ON slice.id = (
205  SELECT s.id
206  FROM thread_slice s
207  WHERE
208    s.name = 'WebMediaPlayerImpl::OnEnded'
209    AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = AVStart.playback_id
210    AND s.upid = AVStart.upid
211  ORDER BY s.ts ASC
212  LIMIT 1
213)
214WHERE NOT EXISTS (
215  SELECT 1 FROM SeekStart
216  WHERE SeekStart.playback_id = AVStart.playback_id
217);
218
219--------------------------------------------------------------------------------
220-- Find maximum video roughness and freezing events per playback.
221
222DROP VIEW IF EXISTS VideoRoughness;
223CREATE VIEW VideoRoughness AS
224SELECT
225  playback_id,
226  playback_start,
227  PlaybackStart.upid,
228  MAX(EXTRACT_ARG(s.arg_set_id, 'debug.roughness')) AS roughness
229FROM PlaybackStart
230INNER JOIN thread_slice s
231WHERE
232  s.name = 'VideoPlaybackRoughness'
233  AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = playback_id
234  AND s.upid = PlaybackStart.upid
235GROUP BY playback_id, playback_start, PlaybackStart.upid;
236
237DROP VIEW IF EXISTS VideoFreezing;
238CREATE VIEW VideoFreezing AS
239SELECT
240  playback_id,
241  playback_start,
242  PlaybackStart.upid,
243  MAX(EXTRACT_ARG(s.arg_set_id, 'debug.freezing')) AS freezing
244FROM PlaybackStart
245INNER JOIN thread_slice s
246WHERE
247  s.name = 'VideoPlaybackFreezing'
248  AND EXTRACT_ARG(s.arg_set_id, 'debug.id') = playback_id
249  AND s.upid = PlaybackStart.upid
250GROUP BY playback_id, playback_start, PlaybackStart.upid;
251
252--------------------------------------------------------------------------------
253-- Output to proto
254
255DROP VIEW IF EXISTS media_metric_output;
256CREATE VIEW media_metric_output AS
257SELECT MediaMetric(
258  'time_to_video_play', (
259    SELECT RepeatedField((video_start - playback_start) / 1e6)
260    FROM VideoStart
261  ),
262  'time_to_audio_play', (
263    SELECT RepeatedField((audio_start - playback_start) / 1e6)
264    FROM AudioStart
265  ),
266  'dropped_frame_count', (
267    SELECT RepeatedField(CAST(dropped_frame_count AS INTEGER))
268    FROM DroppedFrameCount
269  ),
270  'buffering_time', (
271    SELECT RepeatedField((playback_end - duration - av_start) / 1e6)
272    FROM PlaybackEnd
273  ),
274  'roughness', (
275    SELECT RepeatedField(roughness / 1e0)
276    FROM VideoRoughness
277  ),
278  'freezing', (
279    SELECT RepeatedField(freezing / 1e0)
280    FROM VideoFreezing
281  ),
282  'seek_time', (
283    SELECT RepeatedField((seek_complete - seek_start) / 1e6)
284    FROM ValidSeek
285  ),
286  'pipeline_seek_time', (
287    SELECT RepeatedField((pipeline_seek - seek_start) / 1e6)
288    FROM ValidSeek
289  )
290);
291