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