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

Unified Diff: tracing/tracing/metrics/media_metric.html

Issue 3020433002: Finish migrating media metrics to TBMv2 (Closed)
Patch Set: Remove an unnecessary if Created 3 years, 3 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tracing/tracing/metrics/media_metric_test.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tracing/tracing/metrics/media_metric.html
diff --git a/tracing/tracing/metrics/media_metric.html b/tracing/tracing/metrics/media_metric.html
index 3e86e7d26a9025fd0ad49bd7c485c5bdc9a1e564..2e3f90f50cffa49dba775c5f9c02815b3f39f142 100644
--- a/tracing/tracing/metrics/media_metric.html
+++ b/tracing/tracing/metrics/media_metric.html
@@ -18,11 +18,17 @@ This metric currently supports the following measurement:
to wait longer before the videos start actually playing.
* time_to_audio_play is similar to time_to_video_play, but measures the
time delay before audio starts playing.
-
-More measurements are expected to be added in the near future, such as:
-* buffering_time
-* seek_time
-* dropped_frame_count
+* buffering_time calculates the difference between the actual play time of
+ media vs its expected play time. Ideally the two should be the same.
+ If actual play time is significantly longer than expected play time,
+ it indicates that there were stalls during the play for buffering or
+ some other reasons.
+* dropped_frame_count reports the number of video frames that were dropped.
+ Ideally this should be 0. If a large number of frames are dropped, the
+ video play will not be smooth.
+* seek_time calculates how long after a user requests a seek operation
+ before the seek completes and the media starts playing at the new
+ location.
Please inform crouleau@chromium.org and johnchen@chromium.org about
changes to this file.
@@ -37,10 +43,6 @@ changes to this file.
tr.exportTo('tr.metrics', function() {
function mediaMetric(histograms, model) {
- let playStart;
- let timeToAudioPlay;
- let timeToVideoPlay;
-
const chromeHelper = model.getOrCreateHelper(
tr.model.helpers.ChromeModelHelper);
if (chromeHelper === undefined) return;
@@ -56,54 +58,145 @@ tr.exportTo('tr.metrics', function() {
rendererHelper.process.findAtMostOneThreadNamed('AudioOutputDevice');
if (compositorThread === undefined && audioThread === undefined) continue;
- // Look for the media player DoLoad event on main thread.
- for (const event of mainThread.getDescendantEvents()) {
- if (event.title === 'WebMediaPlayerImpl::DoLoad') {
- // TODO(johnchen@chromium.org): Support multiple audio/video
- // elements per page. Currently, we only support a single
- // audio or video element, so we can store the start time in
- // a simple variable, and exit the loop.
- if (playStart !== undefined) {
- throw new Error(
- 'Loading multiple audio/video elements not yet supported');
- }
- playStart = event.start;
- break;
- }
- }
+ const playStart = getPlayStart(mainThread);
if (playStart === undefined) continue;
- // Look for video render event.
- if (compositorThread !== undefined) {
- for (const event of compositorThread.getDescendantEvents()) {
- if (event.title === 'VideoRendererImpl::Render') {
- timeToVideoPlay = event.start - playStart;
- break;
- }
+ const timeToVideoPlay = compositorThread === undefined ? undefined :
+ getTimeToVideoPlay(compositorThread, playStart);
+ const timeToAudioPlay = audioThread === undefined ? undefined :
+ getTimeToAudioPlay(audioThread, playStart);
+
+ if (timeToVideoPlay === undefined && timeToAudioPlay === undefined) {
+ continue;
+ }
+
+ const droppedFrameCount = timeToVideoPlay === undefined ? undefined :
+ getDroppedFrameCount(compositorThread);
+ const seekTimes = timeToVideoPlay === undefined ? new Map() :
+ getSeekTimes(mainThread);
+ const bufferingTime = seekTimes.size !== 0 ? undefined :
+ getBufferingTime(mainThread, playStart, timeToVideoPlay,
+ timeToAudioPlay);
+
+ if (timeToVideoPlay !== undefined) {
+ histograms.createHistogram('time_to_video_play',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ timeToVideoPlay);
+ }
+ if (timeToAudioPlay !== undefined) {
+ histograms.createHistogram('time_to_audio_play',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
+ timeToAudioPlay);
+ }
+ if (droppedFrameCount !== undefined) {
+ histograms.createHistogram('dropped_frame_count',
+ tr.b.Unit.byName.count_smallerIsBetter, droppedFrameCount);
+ }
+ for (const [key, value] of seekTimes.entries()) {
+ histograms.createHistogram('seek_time_' + key,
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, value);
+ }
+ if (bufferingTime !== undefined) {
+ histograms.createHistogram('buffering_time',
+ tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, bufferingTime);
+ }
+ }
+ }
+
+ function getPlayStart(mainThread) {
+ let playStart;
+ for (const event of mainThread.sliceGroup.getDescendantEvents()) {
+ if (event.title === 'WebMediaPlayerImpl::DoLoad') {
+ // TODO(johnchen@chromium.org): Support multiple audio/video
+ // elements per page. Currently, we only support a single
+ // audio or video element, so we can store the start time in
+ // a simple variable.
+ if (playStart !== undefined) {
+ throw new Error(
+ 'Loading multiple audio/video elements not yet supported');
}
+ playStart = event.start;
}
+ }
+ return playStart;
+ }
- // Look for audio render event.
- if (audioThread !== undefined) {
- for (const event of audioThread.getDescendantEvents()) {
- if (event.title === 'AudioRendererImpl::Render') {
- timeToAudioPlay = event.start - playStart;
- break;
- }
+ function getTimeToVideoPlay(compositorThread, playStart) {
+ for (const event of compositorThread.sliceGroup.getDescendantEvents()) {
+ if (event.title === 'VideoRendererImpl::Render') {
+ return event.start - playStart;
+ }
+ }
+ return undefined;
+ }
+
+ function getTimeToAudioPlay(audioThread, playStart) {
+ for (const event of audioThread.sliceGroup.getDescendantEvents()) {
+ if (event.title === 'AudioRendererImpl::Render') {
+ return event.start - playStart;
+ }
+ }
+ return undefined;
+ }
+
+ function getSeekTimes(mainThread) {
+ // We support multiple seeks per page, as long as they seek to different
+ // target time. Thus the following two variables are maps instead of simple
+ // variables. The key of the maps is event.args.target, which is a numerical
+ // value indicating the target location of the seek, in unit of seconds.
+ // For example, with a seek to 5 seconds mark, event.args.target === 5.
+ const seekStartTimes = new Map();
+ const seekTimes = new Map();
+ for (const event of mainThread.sliceGroup.getDescendantEvents()) {
+ if (event.title === 'WebMediaPlayerImpl::DoSeek') {
+ seekStartTimes.set(event.args.target, event.start);
+ } else if (event.title === 'WebMediaPlayerImpl::OnPipelineSeeked') {
+ const startTime = seekStartTimes.get(event.args.target);
+ if (startTime !== undefined) {
+ seekTimes.set(event.args.target, event.start - startTime);
+ seekStartTimes.delete(event.args.target);
}
}
- if (timeToVideoPlay !== undefined) break;
- if (timeToAudioPlay !== undefined) break;
}
+ return seekTimes;
+ }
+ function getBufferingTime(mainThread, playStart, timeToVideoPlay,
+ timeToAudioPlay) {
+ let playEnd;
+ let duration;
+ for (const event of mainThread.sliceGroup.getDescendantEvents()) {
+ if (event.title === 'WebMediaPlayerImpl::OnEnded') {
+ // TODO(johnchen@chromium.org): Support multiple audio/video
+ // elements per page. Currently, we only support a single
+ // audio or video element, so we can store the end time in
+ // a simple variable.
+ if (playEnd !== undefined) {
+ throw new Error(
+ 'Multiple media ended events not yet supported');
+ }
+ playEnd = event.start;
+ duration = 1000 * event.args.duration; // seconds to milliseconds
+ }
+ }
+ if (playEnd === undefined) return undefined;
+ let bufferingTime = playEnd - playStart - duration;
if (timeToVideoPlay !== undefined) {
- histograms.createHistogram('time_to_video_play',
- tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, timeToVideoPlay);
+ bufferingTime -= timeToVideoPlay;
+ } else {
+ bufferingTime -= timeToAudioPlay;
}
- if (timeToAudioPlay !== undefined) {
- histograms.createHistogram('time_to_audio_play',
- tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, timeToAudioPlay);
+ return bufferingTime;
+ }
+
+ function getDroppedFrameCount(compositorThread) {
+ let droppedFrameCount = 0;
+ for (const event of compositorThread.sliceGroup.getDescendantEvents()) {
+ if (event.title === 'VideoFramesDropped') {
+ droppedFrameCount += event.args.count;
+ }
}
+ return droppedFrameCount;
}
tr.metrics.MetricRegistry.register(mediaMetric);
« no previous file with comments | « no previous file | tracing/tracing/metrics/media_metric_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698