blob: 8c3570316cbcc6e71f944cd2157df051c5baf313 [file] [log] [blame]
# Copyright 2014 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.
import json
import logging
import re
from telemetry.internal.util import camel_case
from telemetry.value import list_of_scalar_values
from metrics import Metric
INTERESTING_METRICS = {
'googDecodeMs': {
'units': 'ms',
'description': 'Time spent decoding.',
},
'googMaxDecodeMs': {
'units': 'ms',
'description': 'Maximum time spent decoding one frame.',
},
'googAvgEncodeMs': {
'units': 'ms',
'description': 'Average time spent encoding one frame.'
},
'googRtt': {
'units': 'ms',
'description': 'Measured round-trip time.',
},
'googJitterReceived': {
'units': 'ms',
'description': 'Receive-side jitter in milliseconds.',
},
'googCaptureJitterMs': {
'units': 'ms',
'description': 'Capture device (audio/video) jitter.',
},
'googTargetDelayMs': {
'units': 'ms',
'description': 'The delay we are targeting.',
},
'googExpandRate': {
'units': '%',
'description': 'How much we have NetEQ-expanded the audio (0-100%)',
},
'googFrameRateReceived': {
'units': 'fps',
'description': 'Receive-side frames per second (video)',
},
'googFrameRateSent': {
'units': 'fps',
'description': 'Send-side frames per second (video)',
},
# Bandwidth estimation stats.
'googAvailableSendBandwidth': {
'units': 'bit/s',
'description': 'How much send bandwidth we estimate we have.'
},
'googAvailableReceiveBandwidth': {
'units': 'bit/s',
'description': 'How much receive bandwidth we estimate we have.'
},
'googTargetEncBitrate': {
'units': 'bit/s',
'description': ('The target encoding bitrate we estimate is good to '
'aim for given our bandwidth estimates.')
},
}
def SelectMetrics(particular_metrics):
if not particular_metrics:
return INTERESTING_METRICS
# You can only select among the predefined interesting metrics.
assert set(particular_metrics).issubset(INTERESTING_METRICS.keys())
return {key: value for key, value in INTERESTING_METRICS.iteritems()
if key in particular_metrics}
def GetReportKind(report):
if 'audioInputLevel' in report or 'audioOutputLevel' in report:
return 'audio'
if 'googFrameRateSent' in report or 'googFrameRateReceived' in report:
return 'video'
if 'googAvailableSendBandwidth' in report:
return 'bwe'
logging.debug('Did not recognize report batch: %s.', report.keys())
# There are other kinds of reports, such as transport types, which we don't
# care about here. For these cases just return 'unknown' which will ignore the
# report.
return 'unknown'
def DistinguishAudioVideoOrBwe(report, stat_name):
return GetReportKind(report) + '_' + stat_name
def StripAudioVideoBweDistinction(stat_name):
return re.sub('^(audio|video|bwe)_', '', stat_name)
def SortStatsIntoTimeSeries(report_batches, selected_metrics):
time_series = {}
for report_batch in report_batches:
for report in report_batch:
for stat_name, value in report.iteritems():
if stat_name not in selected_metrics:
continue
if GetReportKind(report) == 'unknown':
continue
full_stat_name = DistinguishAudioVideoOrBwe(report, stat_name)
time_series.setdefault(full_stat_name, []).append(float(value))
return time_series
def PrintSpecialMarkerValue(results):
results.AddValue(list_of_scalar_values.ListOfScalarValues(
results.current_page, 'peer_connection_5_not_logging_more_conns',
'', [17], description=('This marker signifies we never log more '
'than 5 peer connections'),
important=False))
class WebRtcStatisticsMetric(Metric):
"""Makes it possible to measure stats from peer connections."""
def __init__(self, particular_metrics=None):
super(WebRtcStatisticsMetric, self).__init__()
self._all_reports = None
self._selected_metrics = SelectMetrics(particular_metrics)
def Start(self, page, tab):
pass
def Stop(self, page, tab):
"""Digs out stats from data populated by the javascript in webrtc_cases."""
self._all_reports = tab.EvaluateJavaScript(
'JSON.stringify(window.peerConnectionReports)')
def AddResults(self, tab, results):
if not self._all_reports:
return
reports = json.loads(self._all_reports)
for i, report in enumerate(reports):
time_series = SortStatsIntoTimeSeries(report, self._selected_metrics)
# Only ever show stats for 5 peer connections, or it's going to look
# insane in the results.
if i > 5:
PrintSpecialMarkerValue(results)
return
for stat_name, values in time_series.iteritems():
stat_name_underscored = camel_case.ToUnderscore(stat_name)
trace_name = 'peer_connection_%d_%s' % (i, stat_name_underscored)
general_name = StripAudioVideoBweDistinction(stat_name)
results.AddValue(list_of_scalar_values.ListOfScalarValues(
results.current_page, trace_name,
INTERESTING_METRICS[general_name]['units'], values,
description=INTERESTING_METRICS[general_name]['description'],
important=False))