1 from __future__ import division 2 3 from autotest_lib.client.common_lib.cros.cfm.metrics import ( 4 media_info_metrics_extractor) 5 6 MEDIA_TYPE = media_info_metrics_extractor.MediaType 7 DIRECTION = media_info_metrics_extractor.Direction 8 9 # Delta used to determine if floating point values are equal. 10 FLOATING_POINT_COMPARISON_DELTA = 0.00001 11 12 def _avg(l): 13 """ 14 Returns the average of the list or 0 if the list is empty. 15 """ 16 return sum(l)/len(l) if l else 0 17 18 19 def _max(l): 20 """ 21 Returns the max of the list or 0 if the list is empty. 22 """ 23 return max(l) if l else 0 24 25 26 def _get_number_of_incoming_active_video_streams(extractor): 27 """ 28 Calculates the number of incoming video streams. 29 30 @param extractor media_info_metrics_extractor.MediaInfoMetricsExtractor. 31 32 @returns List with (timestamp, number of incoming video streams) tuples. 33 """ 34 # Get metrics of a kind we know exists and count the nuber of values 35 # for each data point. 36 fps_metrics = extractor.get_media_metric( 37 'fps', direction=DIRECTION.RECEIVER, media_type=MEDIA_TYPE.VIDEO) 38 return [(x, [len(y)]) for x, y in fps_metrics] 39 40 41 # Sum for all received streams per data point. 42 BROWSER_CPU_PERCENT_OF_TOTAL = 'browser_cpu_percent' 43 CPU_PERCENT_OF_TOTAL = 'cpu_percent' 44 FRAMERATE_CAPTURED = 'framerate_catured' 45 # Mean for all received streams per data point. 46 FRAMERATE_DECODED = 'framerate_decoded' 47 # Max for all received streams per data point. 48 FRAMERATE_DECODED_MAX = 'framerate_decoded_max' 49 # Mean for all received streams per data point. 50 FRAMERATE_RECEIVED = 'framerate_received' 51 # Max for all received streams per data point. 52 FRAMERATE_RECEIVED_MAX = 'framerate_received_max' 53 FRAMERATE_SENT = 'framerate_sent' 54 GPU_PERCENT_OF_TOTAL = 'gpu_cpu_percent' 55 LEAKY_BUCKET_DELAY = 'leaky_bucket_delay' 56 NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS = 'num_active_vid_in_streams' 57 RENDERER_CPU_PERCENT_OF_TOTAL = 'renderer_cpu_percent' 58 SPEECH_EXPAND_RATE = 'speech_expand_rate' 59 VIDEO_RECEIVED_FRAME_HEIGHT = 'video_received_frame_height' 60 VIDEO_RECEIVED_FRAME_HEIGHT_MAX = 'video_received_frame_height_max' 61 VIDEO_RECEIVED_FRAME_WIDTH = 'video_received_frame_width' 62 VIDEO_RECEIVED_FRAME_WIDTH_MAX = 'video_received_frame_width_max' 63 VIDEO_SENT_FRAME_HEIGHT = 'video_sent_frame_height' 64 VIDEO_SENT_FRAME_WIDTH = 'video_sent_frame_width' 65 66 67 # Mapping between metric names and how to extract the named metric using the 68 # MediaInfoMetricsExtractor. 69 METRIC_NAME_TO_EXTRACTOR_FUNC_DICT = { 70 BROWSER_CPU_PERCENT_OF_TOTAL: 71 lambda x: x.get_top_level_metric('browserProcessCpuUsage'), 72 CPU_PERCENT_OF_TOTAL: 73 lambda x: x.get_top_level_metric('systemcpuusage'), 74 FRAMERATE_CAPTURED: 75 lambda x: x.get_media_metric('fps', 76 direction=DIRECTION.SENDER, 77 media_type=MEDIA_TYPE.VIDEO), 78 FRAMERATE_DECODED: 79 lambda x: x.get_media_metric('fpsdecoded', 80 direction=DIRECTION.RECEIVER, 81 media_type=MEDIA_TYPE.VIDEO, 82 post_process_func=_avg), 83 FRAMERATE_DECODED_MAX: 84 lambda x: x.get_media_metric('fpsdecoded', 85 direction=DIRECTION.RECEIVER, 86 media_type=MEDIA_TYPE.VIDEO, 87 post_process_func=_max), 88 FRAMERATE_RECEIVED: 89 lambda x: x.get_media_metric('fpsnetwork', 90 direction=DIRECTION.RECEIVER, 91 media_type=MEDIA_TYPE.VIDEO, 92 post_process_func=_avg), 93 FRAMERATE_RECEIVED_MAX: 94 lambda x: x.get_media_metric('fpsnetwork', 95 direction=DIRECTION.RECEIVER, 96 media_type=MEDIA_TYPE.VIDEO, 97 post_process_func=_max), 98 FRAMERATE_SENT: 99 lambda x: x.get_media_metric('fpsnetwork', 100 direction=DIRECTION.SENDER, 101 media_type=MEDIA_TYPE.VIDEO), 102 GPU_PERCENT_OF_TOTAL: 103 lambda x: x.get_top_level_metric('gpuProcessCpuUsage'), 104 LEAKY_BUCKET_DELAY: 105 lambda x: x.get_media_metric('leakybucketdelay', 106 direction=DIRECTION.BANDWIDTH_ESTIMATION), 107 NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS: 108 _get_number_of_incoming_active_video_streams, 109 SPEECH_EXPAND_RATE: 110 lambda x: x.get_media_metric('speechExpandRate', 111 direction=DIRECTION.RECEIVER, 112 media_type=MEDIA_TYPE.AUDIO, 113 post_process_func=_avg), 114 RENDERER_CPU_PERCENT_OF_TOTAL: 115 lambda x: x.get_top_level_metric('processcpuusage'), 116 VIDEO_RECEIVED_FRAME_WIDTH: 117 lambda x: x.get_media_metric('width', 118 direction=DIRECTION.RECEIVER, 119 media_type=MEDIA_TYPE.VIDEO, 120 post_process_func=_avg), 121 VIDEO_RECEIVED_FRAME_WIDTH_MAX: 122 lambda x: x.get_media_metric('width', 123 direction=DIRECTION.RECEIVER, 124 media_type=MEDIA_TYPE.VIDEO, 125 post_process_func=_max), 126 VIDEO_RECEIVED_FRAME_HEIGHT: 127 lambda x: x.get_media_metric('height', 128 direction=DIRECTION.RECEIVER, 129 media_type=MEDIA_TYPE.VIDEO, 130 post_process_func=_avg), 131 VIDEO_RECEIVED_FRAME_HEIGHT_MAX: 132 lambda x: x.get_media_metric('height', 133 direction=DIRECTION.RECEIVER, 134 media_type=MEDIA_TYPE.VIDEO, 135 post_process_func=_max), 136 VIDEO_SENT_FRAME_HEIGHT: 137 lambda x: x.get_media_metric('height', 138 direction=DIRECTION.SENDER, 139 media_type=MEDIA_TYPE.VIDEO), 140 VIDEO_SENT_FRAME_WIDTH: 141 lambda x: x.get_media_metric('width', 142 direction=DIRECTION.SENDER, 143 media_type=MEDIA_TYPE.VIDEO), 144 } 145 146 class MetricsCollector(object): 147 """Collects metrics for a test run.""" 148 149 def __init__(self, data_point_collector): 150 """ 151 Initializes. 152 153 @param data_point_collector 154 """ 155 self._data_point_collector = data_point_collector 156 self._extractor = None 157 158 def collect_snapshot(self): 159 """ 160 Stores new merics since the last call. 161 162 Metrics can then be retrieved by calling get_metric. 163 """ 164 self._data_point_collector.collect_snapshot() 165 data_points = self._data_point_collector.get_data_points() 166 # Replace the extractor on each snapshot to always support 167 # getting metrics 168 self._extractor = (media_info_metrics_extractor 169 .MediaInfoMetricsExtractor(data_points)) 170 171 def get_metric(self, name): 172 """ 173 Gets the metric with the specified name. 174 175 @param name The name of the metric 176 @returns a list with (timestamp, value_list) tuples 177 """ 178 if self._extractor is None: 179 raise RuntimeError( 180 'collect_snapshot() must be called at least once.') 181 return METRIC_NAME_TO_EXTRACTOR_FUNC_DICT[name]( 182 self._extractor) 183 184 185 class DataPointCollector(object): 186 """Collects data points.""" 187 188 def __init__(self, cfm_facade): 189 """ 190 Initializes. 191 192 @param cfm_facade The cfm facade to use for getting data points. 193 """ 194 self._cfm_facade = cfm_facade 195 self._data_points = [] 196 197 def collect_snapshot(self): 198 """ 199 Collects any new datapoints since the last collection. 200 """ 201 data_points = self._cfm_facade.get_media_info_data_points() 202 last_timestamp = (self._data_points[-1]['timestamp'] 203 if self._data_points else 0) 204 for data_point in data_points: 205 if (data_point['timestamp'] > 206 last_timestamp + FLOATING_POINT_COMPARISON_DELTA): 207 self._data_points.append(data_point) 208 209 def get_data_points(self): 210 """ 211 Gets all collected data points. 212 """ 213 return self._data_points 214 215