Index: tracing/tracing/metrics/media_metric_test.html |
diff --git a/tracing/tracing/metrics/media_metric_test.html b/tracing/tracing/metrics/media_metric_test.html |
index 64ea02b4b2ea74c171096660d8a55d7b914f8704..a6a29305d5e97d66735fb68be874fc82c2d5e761 100644 |
--- a/tracing/tracing/metrics/media_metric_test.html |
+++ b/tracing/tracing/metrics/media_metric_test.html |
@@ -14,16 +14,81 @@ found in the LICENSE file. |
'use strict'; |
tr.b.unittest.testSuite(function() { |
+ // Arbitrarily selected process ID and thread IDs we'll use in test data |
+ const procId = 52; |
+ const tidMain = 1; |
+ const tidCompositor = 53; |
+ const tidAudio = 55; |
+ |
+ function doLoadEvent(timestamp) { |
+ return {name: 'WebMediaPlayerImpl::DoLoad', args: {}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidMain, ph: 'X'}; |
+ } |
+ |
+ function videoRenderEvent(timestamp) { |
+ return {name: 'VideoRendererImpl::Render', args: {}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidCompositor, ph: 'X'}; |
+ } |
+ |
+ function audioRenderEvent(timestamp) { |
+ return {name: 'AudioRendererImpl::Render', args: {}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidAudio, ph: 'X'}; |
+ } |
+ |
+ function videoFramesDroppedEvent(timestamp, frameCount) { |
+ return {name: 'VideoFramesDropped', args: {count: frameCount}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidCompositor, ph: 'X'}; |
+ } |
+ |
+ function onEndedEvent(timestamp, mediaDuration) { |
+ return {name: 'WebMediaPlayerImpl::OnEnded', |
+ args: {'duration': mediaDuration}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidMain, ph: 'X'}; |
+ } |
+ |
+ function doSeekEvent(timestamp, targetTime) { |
+ return {name: 'WebMediaPlayerImpl::DoSeek', args: {target: targetTime}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidMain, ph: 'X'}; |
+ } |
+ |
+ function seekedEvent(timestamp, targetTime) { |
+ return {name: 'WebMediaPlayerImpl::OnPipelineSeeked', |
+ args: {target: targetTime}, |
+ pid: procId, ts: timestamp, cat: 'media', tid: tidMain, ph: 'X'}; |
+ } |
+ |
+ function threadMarker(threadName, threadId) { |
+ return {name: 'thread_name', args: {name: threadName}, |
+ pid: procId, ts: 0, cat: '__metadata', tid: threadId, ph: 'M'}; |
+ } |
+ |
+ const mainThreadMarker = threadMarker('CrRendererMain', tidMain); |
+ const compositorThreadMarker = threadMarker('Compositor', tidCompositor); |
+ const audioThreadMarker = threadMarker('AudioOutputDevice', tidAudio); |
+ |
function makeModel(events) { |
return tr.c.TestUtils.newModelWithEvents([events]); |
} |
+ function checkCloseTo(histograms, histogramName, expectedValue) { |
+ assert.isDefined(histograms.getHistogramNamed(histogramName)); |
+ const value = histograms.getHistogramNamed(histogramName); |
+ const statistics = value.running; |
+ assert.strictEqual(statistics.count, 1); |
+ assert.closeTo(statistics.mean, expectedValue, 1e-5); |
+ } |
+ |
+ function checkEqual(histograms, histogramName, expectedValue) { |
+ assert.isDefined(histograms.getHistogramNamed(histogramName)); |
+ const value = histograms.getHistogramNamed(histogramName); |
+ const statistics = value.running; |
+ assert.strictEqual(statistics.count, 1); |
+ assert.strictEqual(statistics.mean, expectedValue); |
+ } |
+ |
test('mediaMetric_noData', function() { |
const histograms = new tr.v.HistogramSet(); |
- const events = [ |
- {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
- {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'B'} |
- ]; |
+ const events = []; |
tr.metrics.mediaMetric(histograms, makeModel(events)); |
assert.lengthOf(histograms, 0); |
}); |
@@ -31,47 +96,169 @@ tr.b.unittest.testSuite(function() { |
test('mediaMetric_videoTimeToPlay', function() { |
const histograms = new tr.v.HistogramSet(); |
const events = [ |
- {name: 'WebMediaPlayerImpl::DoLoad', args: {}, |
- pid: 52, ts: 524, cat: 'media', tid: 1, ph: 'X'}, |
- {name: 'VideoRendererImpl::Render', args: {}, |
- pid: 52, ts: 560, cat: 'media', tid: 53, ph: 'X'}, |
- {name: 'VideoRendererImpl::Render', args: {}, |
- pid: 52, ts: 580, cat: 'media', tid: 53, ph: 'X'}, |
- {name: 'thread_name', args: {name: 'CrRendererMain'}, |
- pid: 52, ts: 0, cat: '__metadata', tid: 1, ph: 'M'}, |
- {name: 'thread_name', args: {name: 'Compositor'}, |
- pid: 52, ts: 0, cat: '__metadata', tid: 53, ph: 'M'}, |
+ doLoadEvent(524), |
+ videoRenderEvent(560), |
+ videoRenderEvent(580), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
]; |
tr.metrics.mediaMetric(histograms, makeModel(events)); |
- |
- assert.isDefined(histograms.getHistogramNamed('time_to_video_play')); |
- const ttpValue = histograms.getHistogramNamed('time_to_video_play'); |
- const ttpStatistics = ttpValue.running; |
- assert.strictEqual(ttpStatistics.count, 1); |
- assert.closeTo(ttpStatistics.mean, 0.036, 1e-5); |
- assert.closeTo(ttpStatistics.max, 0.036, 1e-5); |
+ checkCloseTo(histograms, 'time_to_video_play', 0.036); |
}); |
test('mediaMetric_audioTimeToPlay', function() { |
const histograms = new tr.v.HistogramSet(); |
const events = [ |
- {name: 'thread_name', args: {name: 'CrRendererMain'}, |
- pid: 52, ts: 0, cat: '__metadata', tid: 1, ph: 'M'}, |
- {name: 'thread_name', args: {name: 'AudioOutputDevice'}, |
- pid: 52, ts: 0, cat: '__metadata', tid: 53, ph: 'M'}, |
- {name: 'WebMediaPlayerImpl::DoLoad', args: {}, |
- pid: 52, ts: 1234, cat: 'media', tid: 1, ph: 'X'}, |
- {name: 'AudioRendererImpl::Render', args: {}, |
- pid: 52, ts: 4321, cat: 'media', tid: 53, ph: 'X'}, |
+ mainThreadMarker, |
+ audioThreadMarker, |
+ doLoadEvent(1234), |
+ audioRenderEvent(4321), |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkCloseTo(histograms, 'time_to_audio_play', 3.087); |
+ }); |
+ |
+ test('mediaMetric_bufferingTimeVideo', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(1100), |
+ videoRenderEvent(1500), |
+ videoRenderEvent(1600), |
+ onEndedEvent(10066666, 10), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkCloseTo(histograms, 'buffering_time', 65.166); |
+ }); |
+ |
+ test('mediaMetric_bufferingTimeAudio', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ mainThreadMarker, |
+ audioThreadMarker, |
+ doLoadEvent(1234), |
+ audioRenderEvent(4321), |
+ onEndedEvent(5066666, 5), |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkCloseTo(histograms, 'buffering_time', 62.345); |
+ }); |
+ |
+ // With seek, no buffering time should be reported |
+ test('mediaMetric_noBufferingTime', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(1100), |
+ videoRenderEvent(1500), |
+ videoRenderEvent(1600), |
+ onEndedEvent(10066666, 10), |
+ doSeekEvent(525, 1.2), |
+ seekedEvent(719, 1.2), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ assert.isUndefined(histograms.getHistogramNamed('buffering_time')); |
+ }); |
+ |
+ test('mediaMetric_droppedFrameCount', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(1100), |
+ videoRenderEvent(1500), |
+ videoFramesDroppedEvent(123456, 3), |
+ videoFramesDroppedEvent(234567, 6), |
+ videoFramesDroppedEvent(345678, 1), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkEqual(histograms, 'dropped_frame_count', 10); |
+ }); |
+ |
+ test('mediaMetric_seekTime', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(100), |
+ videoRenderEvent(200), |
+ doSeekEvent(524, 1.2), |
+ seekedEvent(719, 1.2), |
+ doSeekEvent(14159, 3.7), |
+ seekedEvent(71828, 3.7), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkCloseTo(histograms, 'seek_time_1.2', 0.195); |
+ checkCloseTo(histograms, 'seek_time_3.7', 57.669); |
+ }); |
+ |
+ // Scenario: Play mixed audio/video from start to finish |
+ test('mediaMetric_playVideoScenario', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(1516), |
+ videoRenderEvent(3257), |
+ audioRenderEvent(3266), |
+ videoRenderEvent(3287), |
+ videoFramesDroppedEvent(123456, 4), |
+ videoFramesDroppedEvent(234567, 2), |
+ onEndedEvent(10012345, 10), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
+ audioThreadMarker, |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkCloseTo(histograms, 'time_to_video_play', 1.741); |
+ checkCloseTo(histograms, 'time_to_audio_play', 1.75); |
+ checkCloseTo(histograms, 'buffering_time', 9.088); |
+ checkEqual(histograms, 'dropped_frame_count', 6); |
+ }); |
+ |
+ // Scenario: Play audio from start to finish |
+ test('mediaMetric_playAudioScenario', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(1516), |
+ audioRenderEvent(3266), |
+ onEndedEvent(10012345, 10), |
+ mainThreadMarker, |
+ audioThreadMarker, |
]; |
tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ assert.isUndefined(histograms.getHistogramNamed('time_to_video_play')); |
+ checkCloseTo(histograms, 'time_to_audio_play', 1.75); |
+ checkCloseTo(histograms, 'buffering_time', 9.079); |
+ assert.isUndefined(histograms.getHistogramNamed('dropped_frame_count')); |
+ }); |
- assert.isDefined(histograms.getHistogramNamed('time_to_audio_play')); |
- const ttpValue = histograms.getHistogramNamed('time_to_audio_play'); |
- const ttpStatistics = ttpValue.running; |
- assert.strictEqual(ttpStatistics.count, 1); |
- assert.closeTo(ttpStatistics.mean, 3.087, 1e-5); |
- assert.closeTo(ttpStatistics.max, 3.087, 1e-5); |
+ // Scenario: Play audio/video with two seeks |
+ test('mediaMetric_seekScenario', function() { |
+ const histograms = new tr.v.HistogramSet(); |
+ const events = [ |
+ doLoadEvent(1516), |
+ videoRenderEvent(3257), |
+ audioRenderEvent(3266), |
+ videoRenderEvent(3287), |
+ doSeekEvent(5123, 0.5), |
+ seekedEvent(5234, 0.5), |
+ videoFramesDroppedEvent(123456, 4), |
+ doSeekEvent(222222, 9), |
+ seekedEvent(222444, 9), |
+ videoFramesDroppedEvent(234567, 2), |
+ onEndedEvent(1234567, 10), |
+ mainThreadMarker, |
+ compositorThreadMarker, |
+ audioThreadMarker, |
+ ]; |
+ tr.metrics.mediaMetric(histograms, makeModel(events)); |
+ checkCloseTo(histograms, 'time_to_video_play', 1.741); |
+ checkCloseTo(histograms, 'time_to_audio_play', 1.75); |
+ assert.isUndefined(histograms.getHistogramNamed('buffering_time')); |
+ checkEqual(histograms, 'dropped_frame_count', 6); |
+ checkCloseTo(histograms, 'seek_time_0.5', 0.111); |
+ checkCloseTo(histograms, 'seek_time_9', 0.222); |
}); |
}); |
</script> |