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 self._system_metrics_collector.post_collect() 54 55 def upload_metrics(self): 56 """ 57 Uploads collected metrics. 58 """ 59 self._upload_system_metrics() 60 self._upload_media_metrics() 61 62 def _collect_snapshots_until_stopped(self): 63 while not self._stop.wait(10): 64 self._system_metrics_collector.collect_snapshot() 65 self._media_metrics_collector.collect_snapshot() 66 67 def _upload_system_metrics(self): 68 self._system_metrics_collector.write_metrics(self._writer_function) 69 70 def _get_jmi_data(self, data_type): 71 """ 72 Gets jmi data for the given data type. 73 74 @param data_type: Type of data to be retrieved from jmi data logs. 75 @return Data for given data type from jmidata log. 76 """ 77 timestamped_values = self._media_metrics_collector.get_metric(data_type) 78 # Strip timestamps. 79 values = [x[1] for x in timestamped_values] 80 # Each entry in values is a list, extract the raw values: 81 res = [] 82 for value_list in values: 83 res.extend(value_list) 84 # Ensure we always return at least one element, or perf uploads will 85 # be sad. 86 return res or [0] 87 88 def _get_last_value(self, data_type): 89 """ 90 Gets last value of a list of numbers. 91 92 @param data_type: Type of data to be retrieved from jmi data log. 93 @return The last value in the jmidata for the specified data_type. 0 if 94 there are no values in the jmidata for this data_type. 95 """ 96 data = self._get_jmi_data(data_type) 97 if not data: 98 return 0 99 return data[-1] 100 101 def _upload_media_metrics(self): 102 """ 103 Write jmidata results to results-chart.json file for Perf Dashboard. 104 """ 105 # Video/Sender metrics 106 self._writer_function( 107 description='avg_encode_ms', 108 value=self._get_jmi_data(media_metrics_collector.AVG_ENCODE_MS), 109 units='ms', 110 higher_is_better=False) 111 112 self._writer_function( 113 description='vid_out_frame_height', # video_out_res 114 value=self._get_jmi_data(media_metrics_collector. 115 VIDEO_SENT_FRAME_HEIGHT), 116 units='px', 117 higher_is_better=True) 118 119 self._writer_function( 120 description='vid_out_frame_width', 121 value=self._get_jmi_data(media_metrics_collector. 122 VIDEO_SENT_FRAME_WIDTH), 123 units='px', 124 higher_is_better=True) 125 126 self._writer_function( 127 description='vid_out_framerate_captured', 128 value=self._get_jmi_data(media_metrics_collector. 129 FRAMERATE_CAPTURED), 130 units='fps', 131 higher_is_better=True) 132 133 self._writer_function( 134 description='vid_out_framerate_encoded', 135 value=self._get_jmi_data(media_metrics_collector. 136 FRAMERATE_ENCODED), 137 units='fps', 138 higher_is_better=True) 139 140 self._writer_function( 141 description='vid_out_sent_packets', 142 value=self._get_last_value(media_metrics_collector. 143 VIDEO_SENT_PACKETS), 144 units='packets', 145 higher_is_better=True) 146 147 # Video/Receiver metrics 148 self._writer_function( 149 description='vid_in_framerate_received', 150 value=self._get_jmi_data(media_metrics_collector. 151 FRAMERATE_NETWORK_RECEIVED), 152 units='fps', 153 higher_is_better=True) 154 155 self._writer_function( 156 description='vid_in_framerate_decoded', 157 value=self._get_jmi_data(media_metrics_collector.FRAMERATE_DECODED), 158 units='fps', 159 higher_is_better=True) 160 161 self._writer_function( 162 description='vid_in_framerate_to_renderer', 163 value=self._get_jmi_data(media_metrics_collector. 164 FRAMERATE_TO_RENDERER), 165 units='fps', 166 higher_is_better=True) 167 168 self._writer_function( 169 description='video_in_frame_heigth', # video_in_res 170 value=self._get_jmi_data(media_metrics_collector. 171 VIDEO_RECEIVED_FRAME_HEIGHT), 172 units='px', 173 higher_is_better=True) 174 175 self._writer_function( 176 description='vid_in_frame_width', 177 value=self._get_jmi_data(media_metrics_collector. 178 VIDEO_RECEIVED_FRAME_WIDTH), 179 units='px', 180 higher_is_better=True) 181 182 # Adaptation metrics 183 self._writer_function( 184 description='vid_out_adapt_changes', 185 value=self._get_last_value(media_metrics_collector. 186 ADAPTATION_CHANGES), 187 units='count', 188 higher_is_better=False) 189 190 self._writer_function( 191 description='vid_out_adapt_reasons', 192 value=self._get_jmi_data(media_metrics_collector.ADAPTATION_REASON), 193 units='reasons', 194 higher_is_better=False) 195 196 # System metrics 197 self._writer_function( 198 description='cpu_usage_jmi', 199 value=self._get_jmi_data(media_metrics_collector. 200 CPU_PERCENT_OF_TOTAL), 201 units='percent', 202 higher_is_better=False) 203 204 self._writer_function( 205 description='process_js_memory', 206 value=[(x / (1024 * 1024)) for x in self._get_jmi_data( 207 media_metrics_collector.PROCESS_JS_MEMORY_USED)], 208 units='MB', 209 higher_is_better=False) 210 211 self._writer_function( 212 description='renderer_cpu_usage', 213 value=self._get_jmi_data( 214 media_metrics_collector.RENDERER_CPU_PERCENT_OF_TOTAL), 215 units='percent', 216 higher_is_better=False) 217 218 self._writer_function( 219 description='browser_cpu_usage', 220 value=self._get_jmi_data( 221 media_metrics_collector.BROWSER_CPU_PERCENT_OF_TOTAL), 222 units='percent', 223 higher_is_better=False) 224 225 self._writer_function( 226 description='gpu_cpu_usage', 227 value=self._get_jmi_data( 228 media_metrics_collector.GPU_PERCENT_OF_TOTAL), 229 units='percent', 230 higher_is_better=False) 231 232 # Other 233 self._writer_function( 234 description='active_streams', 235 value=self._get_jmi_data(media_metrics_collector. 236 NUMBER_OF_ACTIVE_INCOMING_VIDEO_STREAMS), 237 units='count', 238 higher_is_better=True) 239