Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: tools/perf/page_sets/mse_cases/startup_test.js

Issue 71303007: Add MSE perf Telemetry tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: cleaning cases.json Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/perf/page_sets/mse_cases/startup_test.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 (function() {
2 function getPerfTimestamp() {
3 return performance.now();
4 }
5
6 var pageStartTime = getPerfTimestamp();
7 var bodyLoadTime;
8 var pageEndTime;
9
10 function parseQueryParameters() {
11 var params = {};
12 var r = /([^&=]+)=?([^&]*)/g;
13
14 function d(s) { return decodeURIComponent(s.replace(/\+/g, ' ')); }
15
16 var match;
17 while (match = r.exec(window.location.search.substring(1)))
18 params[d(match[1])] = d(match[2]);
19
20 return params;
21 }
22
23 var testParams;
24 function loadTestParams() {
25 var queryParameters = parseQueryParameters();
26 testParams = {};
27 testParams.testType = queryParameters["testType"] || "AV";
28 testParams.useAppendStream = (queryParameters["useAppendStream"] == "true");
29 testParams.doNotWaitForBodyOnLoad = (queryParameters["doNotWaitForBodyOnLoad "] == "true");
30 testParams.startOffset = 0;
31 testParams.appendSize = parseInt(queryParameters["appendSize"] || "65536");
32 testParams.graphDuration = parseInt(queryParameters["graphDuration"] || "100 0");
33 }
34
35 function plotTimestamps(timestamps, graphDuration, element) {
36 var c = document.getElementById('c');
37 var ctx = c.getContext('2d');
38
39 var bars = [
40 { label: 'Page Load Total',
41 start: pageStartTime,
42 end: pageEndTime,
43 color: '#404040' },
44 { label: 'body.onload Delay',
45 start: pageStartTime,
46 end: bodyLoadTime,
47 color: '#808080' },
48 { label: 'Test Total',
49 start: timestamps.testStartTime,
50 end: timestamps.testEndTime,
51 color: '#00FF00' },
52 { label: 'MediaSource opening',
53 start: timestamps.mediaSourceOpenStartTime,
54 end: timestamps.mediaSourceOpenEndTime,
55 color: '#008800' }
56 ];
57
58 var maxAppendEndTime = 0;
59 for (var i = 0; i < timestamps.appenders.length; ++i) {
60 var appender = timestamps.appenders[i];
61 bars.push({ label: 'XHR',
62 start: appender.xhrStartTime,
63 end: appender.xhrEndTime,
64 color: '#0088FF' });
65 bars.push({ label: 'Append',
66 start: appender.appendStartTime,
67 end: appender.appendEndTime,
68 color: '#00FFFF' });
69 if (appender.appendEndTime > maxAppendEndTime) {
70 maxAppendEndTime = appender.appendEndTime;
71 }
72 }
73
74 bars.push({label: 'Post Append Delay', start: maxAppendEndTime, end: timesta mps.testEndTime, color: '#B0B0B0' });
75
76 var minTimestamp = Number.MAX_VALUE;
77 for (var i = 0; i < bars.length; ++i) {
78 minTimestamp = Math.min(minTimestamp, bars[i].start);
79 }
80
81 var graphWidth = c.width - 100;
82 function convertTimestampToX(t) {
83 return graphWidth * (t - minTimestamp) / graphDuration;
84 }
85 var y = 0;
86 var barThickness = 20;
87 c.height = bars.length * barThickness;
88 ctx.font = (0.75 * barThickness) + 'px arial';
89 for (var i = 0; i < bars.length; ++i) {
90 var bar = bars[i];
91 var xStart = convertTimestampToX(bar.start);
92 var xEnd = convertTimestampToX(bar.end);
93 ctx.fillStyle = bar.color;
94 ctx.fillRect(xStart, y, xEnd - xStart, barThickness);
95
96 ctx.fillStyle = 'black';
97 var text = bar.label + ' (' + (bar.end - bar.start).toFixed(3) + ' ms)';
98 ctx.fillText(text, xEnd + 10, y + (0.75 * barThickness));
99 y += barThickness;
100 }
101 reportTelemetryMediaMetrics(bars, element);
102 }
103
104 function displayResults(stats) {
105 var statsDiv = document.getElementById('stats');
106
107 if (!stats) {
108 statsDiv.innerHTML = "Test failed";
109 return;
110 }
111
112 var statsMarkup = "Test passed<br><table>";
113 for (var i in stats) {
114 statsMarkup += "<tr><td style=\"text-align:right\">" + i + ":</td><td>" + stats[i].toFixed(3) + " ms</td>";
115 }
116 statsMarkup += "</table>";
117 statsDiv.innerHTML = statsMarkup;
118 }
119
120 function reportTelemetryMediaMetrics(stats, element) {
121 if (!stats || !window.__getMediaMetric) {
122 console.error("Stats not collected or could not find getMediaMetric().");
123 return;
124 }
125 var metric = window.__getMediaMetric(element);
126 if (!metric) {
127 console.error("Can not report Telemetry media metrics.");
128 return
129 }
130 for (var i = 0; i < stats.length; ++i) {
131 var bar = stats[i];
132 var label = bar.label.toLowerCase().replace(/\s+|\./g, '_');
133 var value = (bar.end - bar.start).toFixed(3);
134 console.log("appending to telemetry " + label + " : " + value);
135 metric.appendMetric("mse_" + label, value);
136 }
137 }
138
139 function updateControls(testParams) {
140 var testTypeElement = document.getElementById("testType");
141 for (var i in testTypeElement.options) {
142 var option = testTypeElement.options[i];
143 if (option.value == testParams.testType) {
144 testTypeElement.selectedIndex = option.index;
145 }
146 }
147
148 document.getElementById("useAppendStream").checked = testParams.useAppendStr eam;
149 document.getElementById("doNotWaitForBodyOnLoad").checked = testParams.doNot WaitForBodyOnLoad;
150 document.getElementById("appendSize").value = testParams.appendSize;
151 document.getElementById("graphDuration").value = testParams.graphDuration;
152 }
153
154 function BufferAppender(mimetype, url, id, startOffset, appendSize) {
155 this.mimetype = mimetype;
156 this.url = url;
157 this.id = id;
158 this.startOffset = startOffset;
159 this.appendSize = appendSize;
160 this.xhr = new XMLHttpRequest();
161 this.sourceBuffer = null;
162 }
163
164 BufferAppender.prototype.start = function() {
165 this.xhr.addEventListener('loadend', this.onLoadEnd.bind(this));
166 this.xhr.open('GET', this.url);
167 this.xhr.setRequestHeader('Range', 'bytes=' + this.startOffset + '-' +
168 (this.startOffset + this.appendSize - 1));
169 this.xhr.responseType = 'arraybuffer';
170 this.xhr.send();
171
172 this.xhrStartTime = getPerfTimestamp();
173 };
174
175 BufferAppender.prototype.onLoadEnd = function() {
176 this.xhrEndTime = getPerfTimestamp();
177 this.attemptAppend();
178 };
179
180 BufferAppender.prototype.onSourceOpen = function(mediaSource) {
181 if (this.sourceBuffer)
182 return;
183 this.sourceBuffer = mediaSource.addSourceBuffer(this.mimetype);
184 };
185
186 BufferAppender.prototype.attemptAppend = function() {
187 if (!this.xhr.response || !this.sourceBuffer)
188 return;
189
190 this.appendStartTime = getPerfTimestamp();
191
192 if (this.sourceBuffer.appendBuffer) {
193 this.sourceBuffer.addEventListener('updateend',
194 this.onUpdateEnd.bind(this));
195 this.sourceBuffer.appendBuffer(this.xhr.response);
196 } else {
197 this.sourceBuffer.append(new Uint8Array(this.xhr.response));
198 this.appendEndTime = getPerfTimestamp();
199 }
200
201 this.xhr = null;
202 };
203
204 BufferAppender.prototype.onUpdateEnd = function() {
205 this.appendEndTime = getPerfTimestamp();
206 };
207
208 BufferAppender.prototype.onPlaybackStarted = function() {
209 var now = getPerfTimestamp();
210 this.playbackStartTime = now;
211 if (this.sourceBuffer.updating) {
212 // Still appending but playback has already started so just abort the XHR
213 // and append.
214 this.sourceBuffer.abort();
215 this.xhr.abort();
216 }
217 };
218
219 BufferAppender.prototype.getXHRLoadDuration = function() {
220 return this.xhrEndTime - this.xhrStartTime;
221 };
222
223 BufferAppender.prototype.getAppendDuration = function() {
224 return this.appendEndTime - this.appendStartTime;
225 };
226
227 function StreamAppender(mimetype, url, id, startOffset, appendSize) {
228 this.mimetype = mimetype;
229 this.url = url;
230 this.id = id;
231 this.startOffset = startOffset;
232 this.appendSize = appendSize;
233 this.xhr = new XMLHttpRequest();
234 this.sourceBuffer = null;
235 this.appendStarted = false;
236 }
237
238 StreamAppender.prototype.start = function() {
239 this.xhr.addEventListener('readystatechange',
240 this.attemptAppend.bind(this));
241 this.xhr.addEventListener('loadend', this.onLoadEnd.bind(this));
242 this.xhr.open('GET', this.url);
243 this.xhr.setRequestHeader('Range', 'bytes=' + this.startOffset + '-' +
244 (this.startOffset + this.appendSize - 1));
245 this.xhr.responseType = 'stream';
246 if (this.xhr.responseType != 'stream') {
247 throw "XHR does not support 'stream' responses.";
248 }
249 this.xhr.send();
250
251 this.xhrStartTime = getPerfTimestamp();
252 };
253
254 StreamAppender.prototype.onLoadEnd = function() {
255 this.xhrEndTime = getPerfTimestamp();
256 this.attemptAppend();
257 };
258
259 StreamAppender.prototype.onSourceOpen = function(mediaSource) {
260 if (this.sourceBuffer)
261 return;
262 this.sourceBuffer = mediaSource.addSourceBuffer(this.mimetype);
263 };
264
265 StreamAppender.prototype.attemptAppend = function() {
266 if (this.xhr.readyState < this.xhr.LOADING) {
267 return;
268 }
269
270 if (!this.xhr.response || !this.sourceBuffer || this.appendStarted)
271 return;
272
273 this.appendStartTime = getPerfTimestamp();
274 this.appendStarted = true;
275 this.sourceBuffer.addEventListener('updateend',
276 this.onUpdateEnd.bind(this));
277 this.sourceBuffer.appendStream(this.xhr.response);
278 };
279
280 StreamAppender.prototype.onUpdateEnd = function() {
281 this.appendEndTime = getPerfTimestamp();
282 };
283
284 StreamAppender.prototype.onPlaybackStarted = function() {
285 var now = getPerfTimestamp();
286 this.playbackStartTime = now;
287 if (this.sourceBuffer.updating) {
288 // Still appending but playback has already started so just abort the XHR
289 // and append.
290 this.sourceBuffer.abort();
291 this.xhr.abort();
292 if (!this.appendEndTime)
293 this.appendEndTime = now;
294
295 if (!this.xhrEndTime)
296 this.xhrEndTime = now;
297 }
298 };
299
300 StreamAppender.prototype.getXHRLoadDuration = function() {
301 return this.xhrEndTime - this.xhrStartTime;
302 };
303
304 StreamAppender.prototype.getAppendDuration = function() {
305 return this.appendEndTime - this.appendStartTime;
306 };
307
308 // runAppendTest() sets testDone to true once all appends finish.
309 var testDone = false;
310 function runAppendTest(mediaElement, appenders, doneCallback) {
311 var testStartTime = getPerfTimestamp();
312 var mediaSourceOpenStartTime;
313 var mediaSourceOpenEndTime;
314
315 for (var i = 0; i < appenders.length; ++i) {
316 appenders[i].start();
317 }
318
319 function onSourceOpen(event) {
320 var mediaSource = event.target;
321
322 mediaSourceOpenEndTime = getPerfTimestamp();
323
324 for (var i = 0; i < appenders.length; ++i) {
325 appenders[i].onSourceOpen(mediaSource);
326 }
327
328 for (var i = 0; i < appenders.length; ++i) {
329 appenders[i].attemptAppend(mediaSource);
330 }
331
332 mediaElement.play();
333 }
334
335 var mediaSource;
336 if (window['MediaSource']) {
337 mediaSource = new window.MediaSource();
338 mediaSource.addEventListener('sourceopen', onSourceOpen);
339 } else {
340 mediaSource = new window.WebKitMediaSource();
341 mediaSource.addEventListener('webkitsourceopen', onSourceOpen);
342 }
343
344 var listener;
345 var timeout;
346 function checkForCurrentTimeChange() {
347 if (testDone)
348 return;
349
350 if (mediaElement.readyState < mediaElement.HAVE_METADATA ||
351 mediaElement.currentTime <= 0)
352 return;
353
354 for (var i = 0; i < appenders.length; ++i) {
355 appenders[i].onPlaybackStarted(mediaSource);
356 }
357
358 var testEndTime = getPerfTimestamp();
359
360 testDone = true;
361 window.clearInterval(listener);
362 window.clearTimeout(timeout);
363
364 var stats = {};
365 stats.total = testEndTime - testStartTime;
366 stats.sourceOpen = mediaSourceOpenEndTime - mediaSourceOpenStartTime;
367 stats.maxXHRLoadDuration = appenders[0].getXHRLoadDuration();
368 stats.maxAppendDuration = appenders[0].getAppendDuration();
369
370 var timestamps = {};
371 timestamps.testStartTime = testStartTime;
372 timestamps.testEndTime = testEndTime;
373 timestamps.mediaSourceOpenStartTime = mediaSourceOpenStartTime;
374 timestamps.mediaSourceOpenEndTime = mediaSourceOpenEndTime;
375 timestamps.appenders = [];
376
377 for (var i = 1; i < appenders.length; ++i) {
378 var appender = appenders[i];
379 var xhrLoadDuration = appender.getXHRLoadDuration();
380 var appendDuration = appender.getAppendDuration();
381
382 if (xhrLoadDuration > stats.maxXHRLoadDuration)
383 stats.maxXHRLoadDuration = xhrLoadDuration;
384
385 if (appendDuration > stats.maxAppendDuration)
386 stats.maxAppendDuration = appendDuration;
387 }
388
389 for (var i = 0; i < appenders.length; ++i) {
390 var appender = appenders[i];
391 var appenderTimestamps = {};
392 appenderTimestamps.xhrStartTime = appender.xhrStartTime;
393 appenderTimestamps.xhrEndTime = appender.xhrEndTime;
394 appenderTimestamps.appendStartTime = appender.appendStartTime;
395 appenderTimestamps.appendEndTime = appender.appendEndTime;
396 appenderTimestamps.playbackStartTime = appender.playbackStartTime;
397 timestamps.appenders.push(appenderTimestamps);
398 }
399
400 mediaElement.pause();
401
402 pageEndTime = getPerfTimestamp();
403 doneCallback(stats, timestamps);
404 };
405
406 mediaElement.addEventListener('timeupdate', checkForCurrentTimeChange);
407
408 listener = setInterval(checkForCurrentTimeChange, 15);
409 timeout = setTimeout(function() {
410 if (testDone)
411 return;
412
413 console.log('Test timed out.');
414 testDone = true;
415 window.clearInterval(listener);
416
417 mediaElement.pause();
418 doneCallback(null);
419 }, 10000);
420
421 mediaSourceOpenStartTime = getPerfTimestamp();
422 mediaElement.src = URL.createObjectURL(mediaSource);
423 };
424
425 function onBodyLoad() {
426 bodyLoadTime = getPerfTimestamp();
427
428 if (!testParams.doNotWaitForBodyOnLoad) {
429 startTest();
430 }
431 }
432
433 function startTest() {
434 updateControls(testParams);
435
436 var appenders = [];
437
438 if (useAppendStream && !window.MediaSource)
439 throw "Can't use appendStream() because the unprefixed MediaSource object is not present.";
440
441 var Appender = testParams.useAppendStream ? StreamAppender : BufferAppender;
442
443 if (testParams.testType.indexOf("A") != -1) {
444 appenders.push(new Appender("audio/mp4; codecs=\"mp4a.40.2\"", "audio.mp4" , "a", testParams.startOffset, testParams.appendSize));
445 }
446
447 if (testParams.testType.indexOf("V") != -1) {
448 appenders.push(new Appender("video/mp4; codecs=\"avc1.640028\"", "video.mp 4", "v", testParams.startOffset, testParams.appendSize));
449 }
450
451 var video = document.getElementById('v');
452 video.id = getTestID();
453 runAppendTest(video, appenders, function(stats, timestamps) {
454 displayResults(stats);
455 plotTimestamps(timestamps, testParams.graphDuration, video);
456 });
457 }
458
459 function getTestID() {
460 console.log("setting test ID")
461 console.log(testParams.doNotWaitForBodyOnLoad)
462 var id = testParams.testType;
463 if (testParams.useAppendStream)
464 id += "_stream"
465 else
466 id += "_buffer"
467 if (testParams.doNotWaitForBodyOnLoad)
468 id += "_pre_load"
469 else
470 id += "_post_load"
471 return id;
472 }
473
474 function setupTest() {
475 loadTestParams();
476 document.body.onload = onBodyLoad;
477
478 if (testParams.doNotWaitForBodyOnLoad) {
479 startTest();
480 }
481 }
482
483 window["setupTest"] = setupTest;
484 window.__testDone = function() {
485 return testDone;
486 };
487 })();
OLDNEW
« no previous file with comments | « tools/perf/page_sets/mse_cases/startup_test.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698