1import threading 2 3from autotest_lib.client.common_lib.cros import system_metrics_collector 4from autotest_lib.client.common_lib.cros.cfm.metrics import ( 5 media_metrics_collector) 6 7 8class PerfMetricsCollector(object): 9 """ 10 Metrics collector that runs in seprate thread than the caller. 11 """ 12 def __init__(self, system_facade, cfm_facade, writer_function, 13 additional_system_metrics=[]): 14 """ 15 Constructor. 16 17 @param system_facade facade object to access system utils. 18 @param cfm_facade facade object to access cfm utils. 19 @param writer_function function called to collected metrics. 20 @param additional_system_metrics Additional metrics to collect. 21 """ 22 metric_set = system_metrics_collector.create_default_metric_set( 23 system_facade) 24 for metric in additional_system_metrics: 25 metric_set.append(metric) 26 self._system_metrics_collector = ( 27 system_metrics_collector.SystemMetricsCollector(system_facade, 28 metric_set)) 29 # Media metrics 30 data_point_collector = media_metrics_collector.DataPointCollector( 31 cfm_facade) 32 self._media_metrics_collector = (media_metrics_collector 33 .MetricsCollector(data_point_collector)) 34 35 self._writer_function = writer_function 36 # Collector thread. 37 self._collector_thread = threading.Thread( 38 target=self._collect_snapshots_until_stopped) 39 self._stop = threading.Event() 40 41 def start(self): 42 """ 43 Starts metrics collection. 44 """ 45 self._system_metrics_collector.pre_collect() 46 self._collector_thread.start() 47 48 def stop(self): 49 """ 50 Stops metrics collection. 51 """ 52 self._stop.set() 53 54 def upload_metrics(self): 55 """ 56 Uploads collected metrics. 57 """ 58 self._upload_system_metrics() 59 self._upload_media_metrics() 60 61 def _collect_snapshots_until_stopped(self): 62 while not self._stop.wait(10): 63 self._system_metrics_collector.collect_snapshot() 64 self._media_metrics_collector.collect_snapshot() 65 66 def _upload_system_metrics(self): 67 self._system_metrics_collector.write_metrics(self._writer_function) 68 69 def _get_jmi_data(self, data_type): 70 """ 71 Gets jmi data for the given data type. 72 73 @param data_type: Type of data to be retrieved from jmi data logs. 74 @return Data for given data type from jmidata log. 75 """ 76 timestamped_values = self._media_metrics_collector.get_metric(data_type) 77 # Strip timestamps. 78 values = [x[1] for x in timestamped_values] 79 # Each entry in values is a list, extract the raw values: 80 res = [] 81 for value_list in values: 82 res.extend(value_list) 83 # Ensure we always return at least one element, or perf uploads will 84 # be sad. 85 return res or [0] 86 87 def _get_last_value(self, data_type): 88 """ 89 Gets last value of a list of numbers. 90 91 @param data_type: Type of data to be retrieved from jmi data log. 92 @return The last value in the jmidata for the specified data_type. 0 if 93 there are no values in the jmidata for this data_type. 94 """ 95 data = self._get_jmi_data(data_type) 96 if not data: 97 return 0 98 return data[-1] 99 100 def _upload_media_metrics(self): 101 """ 102 Write jmidata results to results-chart.json file for Perf Dashboard. 103 """ 104 # Video/Sender metrics 105 self._writer_function( 106 description='avg_encode_ms', 107 value=self._get_jmi_data(media_metrics_collector.AVG_ENCODE_MS), 108 units='ms', 109 higher_is_better=False) 110 111 self._writer_function( 112 description='vid_out_frame_height', # video_out_res 113 value=self._get_jmi_data(media_metrics_collector. 114 VIDEO_SENT_FRAME_HEIGHT), 115 units='px', 116 higher_is_better=True) 117 118 self._writer_function( 119 description='vid_out_frame_width', 120 value=self._get_jmi_data(media_metrics_collector. 121 VIDEO_SENT_FRAME_WIDTH), 122 units='px', 123 higher_is_better=True) 124 125 self._writer_function( 126 description='vid_out_framerate_captured', 127 value=self._get_jmi_data(media_metrics_collector. 128 FRAMERATE_CAPTURED), 129 units='fps', 130 higher_is_better=True) 131 132 self._writer_function( 133 description='vid_out_framerate_encoded', 134 value=self._get_jmi_data(media_metrics_collector. 135 FRAMERATE_ENCODED), 136 units='fps', 137 higher_is_better=True) 138 139 self._writer_function( 140 description='vid_out_sent_packets', 141 value=self._get_last_value(media_metrics_collector. 142 VIDEO_SENT_PACKETS), 143 units='packets', 144 higher_is_better=True) 145 146 # Video/Receiver metrics 147 self._writer_function( 148 description='vid_in_framerate_received', 149 value=self._get_jmi_data(media_metrics_collector. 150 FRAMERATE_NETWORK_RECEIVED), 151 units='fps', 152 higher_is_better=True) 153 154 self._writer_function( 155 description='vid_in_framerate_decoded', 156 value=self._get_jmi_data(media_metrics_collector.FRAMERATE_DECODED), 157 units='fps', 158 higher_is_better=True) 159 160 self._writer_function( 161 description='vid_in_framerate_to_renderer', 162 value=self._get_jmi_data(media_metrics_collector. 163 FRAMERATE_TO_RENDERER), 164 units='fps', 165 higher_is_better=True) 166 167 self._writer_function( 168 description='video_in_frame_heigth', # video_in_res 169 value=self._get_jmi_data(media_metrics_collector. 170 VIDEO_RECEIVED_FRAME_HEIGHT), 171 units='px', 172 higher_is_better=True) 173 174 self._writer_function( 175 description='vid_in_frame_width', 176 value=self._get_jmi_data(media_metrics_collector. 177 VIDEO_RECEIVED_FRAME_WIDTH), 178 units='px', 179 higher_is_better=True) 180 181 # Adaptation metrics 182 self._writer_function( 183 description='vid_out_adapt_changes', 184 value=self._get_last_value(media_metrics_collector. 185 ADAPTATION_CHANGES), 186 units='count', 187 higher_is_better=False) 188 189 self._writer_function( 190 description='vid_out_adapt_reasons', 191 value=self._get_jmi_data(media_metrics_collector.ADAPTATION_REASON), 192 units='reasons', 193 higher_is_better=False) 194 195 # System metrics 196 self._writer_function( 197 description='cpu_usage_jmi', 198 value=self._get_jmi_data(media_metrics_collector. 199 CPU_PERCENT_OF_TOTAL), 200 units='percent', 201 higher_is_better=False) 202 203 self._writer_function( 204 description='process_js_memory', 205 value=[(x / (1024 * 1024)) for x in self._get_jmi_data( 206 media_metrics_collector.PROCESS_JS_MEMORY_USED)], 207 units='MB', 208 higher_is_better=False) 209 210 self._writer_function( 211 description='renderer_cpu_usage', 212 value=self._get_jmi_data( 213 media_metrics_collector.RENDERER_CPU_PERCENT_OF_TOTAL), 214 units='percent', 215 higher_is_better=False) 216 217 self._writer_function( 218 description='browser_cpu_usage', 219 value=self._get_jmi_data( 220 media_metrics_collector.BROWSER_CPU_PERCENT_OF_TOTAL), 221 units='percent', 222 higher_is_better=False) 223 224 self._writer_function( 225 description='gpu_cpu_usage', 226 value=self._get_jmi_data( 227 media_metrics_collector.GPU_PERCENT_OF_TOTAL), 228 units='percent', 229 higher_is_better=False) 230 231 # Other 232 self._writer_function( 233 description='active_streams', 234 value=self._get_jmi_data(media_metrics_collector. 235 NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS), 236 units='count', 237 higher_is_better=True) 238