blob: 543383f1c2ea17b59b7edef2ab6b6db0fc1b4a41 [file] [log] [blame]
from __future__ import division
from autotest_lib.client.common_lib.cros.cfm.metrics import (
media_info_metrics_extractor)
MEDIA_TYPE = media_info_metrics_extractor.MediaType
DIRECTION = media_info_metrics_extractor.Direction
# Delta used to determine if floating point values are equal.
FLOATING_POINT_COMPARISON_DELTA = 0.00001
def _avg(l):
"""
Returns the average of the list or 0 if the list is empty.
"""
return sum(l)/len(l) if l else 0
def _max(l):
"""
Returns the max of the list or 0 if the list is empty.
"""
return max(l) if l else 0
def _get_number_of_incoming_active_video_streams(extractor):
"""
Calculates the number of incoming video streams.
@param extractor media_info_metrics_extractor.MediaInfoMetricsExtractor.
@returns List with (timestamp, number of incoming video streams) tuples.
"""
# Get metrics of a kind we know exists and count the nuber of values
# for each data point.
fps_metrics = extractor.get_media_metric(
'fps', direction=DIRECTION.RECEIVER, media_type=MEDIA_TYPE.VIDEO)
return [(x, [len(y)]) for x, y in fps_metrics]
# Sum for all received streams per data point.
BROWSER_CPU_PERCENT_OF_TOTAL = 'browser_cpu_percent'
CPU_PERCENT_OF_TOTAL = 'cpu_percent'
FRAMERATE_CAPTURED = 'framerate_catured'
# Mean for all received streams per data point.
FRAMERATE_DECODED = 'framerate_decoded'
# Max for all received streams per data point.
FRAMERATE_DECODED_MAX = 'framerate_decoded_max'
# Mean for all received streams per data point.
FRAMERATE_RECEIVED = 'framerate_received'
# Max for all received streams per data point.
FRAMERATE_RECEIVED_MAX = 'framerate_received_max'
FRAMERATE_SENT = 'framerate_sent'
GPU_PERCENT_OF_TOTAL = 'gpu_cpu_percent'
LEAKY_BUCKET_DELAY = 'leaky_bucket_delay'
NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS = 'num_active_vid_in_streams'
RENDERER_CPU_PERCENT_OF_TOTAL = 'renderer_cpu_percent'
SPEECH_EXPAND_RATE = 'speech_expand_rate'
VIDEO_RECEIVED_FRAME_HEIGHT = 'video_received_frame_height'
VIDEO_RECEIVED_FRAME_HEIGHT_MAX = 'video_received_frame_height_max'
VIDEO_RECEIVED_FRAME_WIDTH = 'video_received_frame_width'
VIDEO_RECEIVED_FRAME_WIDTH_MAX = 'video_received_frame_width_max'
VIDEO_SENT_FRAME_HEIGHT = 'video_sent_frame_height'
VIDEO_SENT_FRAME_WIDTH = 'video_sent_frame_width'
# Mapping between metric names and how to extract the named metric using the
# MediaInfoMetricsExtractor.
METRIC_NAME_TO_EXTRACTOR_FUNC_DICT = {
BROWSER_CPU_PERCENT_OF_TOTAL:
lambda x: x.get_top_level_metric('browserProcessCpuUsage'),
CPU_PERCENT_OF_TOTAL:
lambda x: x.get_top_level_metric('systemcpuusage'),
FRAMERATE_CAPTURED:
lambda x: x.get_media_metric('fps',
direction=DIRECTION.SENDER,
media_type=MEDIA_TYPE.VIDEO),
FRAMERATE_DECODED:
lambda x: x.get_media_metric('fpsdecoded',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_avg),
FRAMERATE_DECODED_MAX:
lambda x: x.get_media_metric('fpsdecoded',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_max),
FRAMERATE_RECEIVED:
lambda x: x.get_media_metric('fpsnetwork',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_avg),
FRAMERATE_RECEIVED_MAX:
lambda x: x.get_media_metric('fpsnetwork',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_max),
FRAMERATE_SENT:
lambda x: x.get_media_metric('fpsnetwork',
direction=DIRECTION.SENDER,
media_type=MEDIA_TYPE.VIDEO),
GPU_PERCENT_OF_TOTAL:
lambda x: x.get_top_level_metric('gpuProcessCpuUsage'),
LEAKY_BUCKET_DELAY:
lambda x: x.get_media_metric('leakybucketdelay',
direction=DIRECTION.BANDWIDTH_ESTIMATION),
NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS:
_get_number_of_incoming_active_video_streams,
SPEECH_EXPAND_RATE:
lambda x: x.get_media_metric('speechExpandRate',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.AUDIO,
post_process_func=_avg),
RENDERER_CPU_PERCENT_OF_TOTAL:
lambda x: x.get_top_level_metric('processcpuusage'),
VIDEO_RECEIVED_FRAME_WIDTH:
lambda x: x.get_media_metric('width',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_avg),
VIDEO_RECEIVED_FRAME_WIDTH_MAX:
lambda x: x.get_media_metric('width',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_max),
VIDEO_RECEIVED_FRAME_HEIGHT:
lambda x: x.get_media_metric('height',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_avg),
VIDEO_RECEIVED_FRAME_HEIGHT_MAX:
lambda x: x.get_media_metric('height',
direction=DIRECTION.RECEIVER,
media_type=MEDIA_TYPE.VIDEO,
post_process_func=_max),
VIDEO_SENT_FRAME_HEIGHT:
lambda x: x.get_media_metric('height',
direction=DIRECTION.SENDER,
media_type=MEDIA_TYPE.VIDEO),
VIDEO_SENT_FRAME_WIDTH:
lambda x: x.get_media_metric('width',
direction=DIRECTION.SENDER,
media_type=MEDIA_TYPE.VIDEO),
}
class MetricsCollector(object):
"""Collects metrics for a test run."""
def __init__(self, data_point_collector):
"""
Initializes.
@param data_point_collector
"""
self._data_point_collector = data_point_collector
self._extractor = None
def collect_snapshot(self):
"""
Stores new merics since the last call.
Metrics can then be retrieved by calling get_metric.
"""
self._data_point_collector.collect_snapshot()
data_points = self._data_point_collector.get_data_points()
# Replace the extractor on each snapshot to always support
# getting metrics
self._extractor = (media_info_metrics_extractor
.MediaInfoMetricsExtractor(data_points))
def get_metric(self, name):
"""
Gets the metric with the specified name.
@param name The name of the metric
@returns a list with (timestamp, value_list) tuples
"""
if self._extractor is None:
raise RuntimeError(
'collect_snapshot() must be called at least once.')
return METRIC_NAME_TO_EXTRACTOR_FUNC_DICT[name](
self._extractor)
class DataPointCollector(object):
"""Collects data points."""
def __init__(self, cfm_facade):
"""
Initializes.
@param cfm_facade The cfm facade to use for getting data points.
"""
self._cfm_facade = cfm_facade
self._data_points = []
def collect_snapshot(self):
"""
Collects any new datapoints since the last collection.
"""
data_points = self._cfm_facade.get_media_info_data_points()
last_timestamp = (self._data_points[-1]['timestamp']
if self._data_points else 0)
for data_point in data_points:
if (data_point['timestamp'] >
last_timestamp + FLOATING_POINT_COMPARISON_DELTA):
self._data_points.append(data_point)
def get_data_points(self):
"""
Gets all collected data points.
"""
return self._data_points