Index: tools/perf/perf_tools/media_measurement.py |
diff --git a/tools/perf/perf_tools/media_measurement.py b/tools/perf/perf_tools/media_measurement.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..92840cde6e241282ddf30d37b620a3e9460c7ed1 |
--- /dev/null |
+++ b/tools/perf/perf_tools/media_measurement.py |
@@ -0,0 +1,107 @@ |
+# Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Media measurement class gathers media related metrics on a page set. |
+ |
+Default media metrics are collected for every media element in the page, such as |
+decoded_frame_count, dropped_frame_count, decoded_video_bytes, and |
+decoded_audio_bytes. |
+""" |
+ |
+import logging |
+import os |
+ |
+from telemetry.page import page_measurement |
+ |
+ |
+class MediaMeasurement(page_measurement.PageMeasurement): |
+ """Provide general video and audio metrics.""" |
+ |
+ def __init__(self): |
+ super(MediaMeasurement, self).__init__('media_metrics') |
+ |
+ def results_are_the_same_on_every_page(self): |
+ """Results can vary from page to page based on media events taking place.""" |
+ return False |
+ |
+ def ReportCollectedMetrics(self, tab, results): |
+ """Reports all recorded metrics as Telemetry perf results. |
+ |
+ Metrics are recorded for each media element in the page. Each metric result |
+ has media info + metric values as a map, for example: |
+ Media metric = { |
+ 'info': { |
+ 'src': 'file.webm', |
+ 'id': 'video1', |
+ ... |
+ }, |
+ 'metrics': { |
+ 'ttp': [120, 'ms'], |
+ 'decoded_bytes': [13233, 'bytes'], |
+ ... |
+ } |
+ } |
+ """ |
+ media_metrics = tab.EvaluateJavaScript('window.__getAllMetrics()') |
nduca
2013/06/17 23:01:33
so you should make a MediaMetrics class that seals
shadi
2013/06/21 00:39:51
Done.
|
+ for media_metric in media_metrics: |
+ self.AddResult(media_metric, results) |
+ |
+ def AddResult(self, media_metric, results): |
nduca
2013/06/17 23:01:33
looks like this doesn't have to be a class method.
shadi
2013/06/21 00:39:51
Done.
|
+ """Adds the media metric result to global results, needed for graphing.""" |
+ info = media_metric['info'] |
+ metrics = media_metric['metrics'] |
+ for metric in metrics: |
+ value, units = GetValueUnit(metrics[metric]) |
+ if not units: |
+ logging.error('Missing units value for media metric %s.', metric) |
+ continue |
+ trace = GetTraceName(info) |
+ results.Add(trace, units, value, chart_name=metric, |
+ data_type='default') |
+ |
+ def LoadDepsJS(self, tab): |
+ """Loads the JS files needed for media metrics, if not already loaded.""" |
+ # Media actions could have already loaded the JS file. |
+ deps_found = tab.EvaluateJavaScript('window.__mediaRecorders != undefined') |
+ if not deps_found: |
+ with open( |
+ os.path.join(os.path.dirname(__file__), 'media_metrics.js')) as f: |
+ js = f.read() |
+ tab.ExecuteJavaScript(js) |
+ |
+ def MeasurePage(self, page, tab, results): |
+ """Measure the page's performance.""" |
+ self.LoadDepsJS(tab) |
nduca
2013/06/17 23:01:33
how bout making this a start/stop pattern and do t
shadi
2013/06/18 00:30:01
I don't see how a start/stop pattern would work fo
|
+ self.ReportCollectedMetrics(tab, results) |
+ |
+ |
+def GetValueUnit(metric): |
+ """Returns a (value, units) pair stored in a metric if available.""" |
+ if isinstance(metric, (list, tuple)): |
+ if len(metric) > 1: |
+ return (metric[0], metric[1]) |
+ else: |
+ return (metric[0], None) |
+ return (metric, None) |
+ |
+ |
+def GetTraceName(info): |
+ """Returns a media trace name based on the metric info map. |
+ |
+ In order, returns the first available: |
+ - 'id' key value. |
+ - file name based on 'src' key value. |
+ - the first key value available. |
+ - 'no_trace'. |
+ """ |
+ if 'id' in info: |
+ return info['id'] |
+ elif 'src' in info: |
+ # Return only file name in src. |
+ src = info['src'] |
+ return src[src.rfind('/') + 1:] |
+ else: |
+ for key in info: |
+ return info[key] |
+ return 'no_trace' |