Home | History | Annotate | Download | only in utils
      1 import threading
      2 
      3 from autotest_lib.client.common_lib.cros import system_metrics_collector
      4 from autotest_lib.client.common_lib.cros.cfm.metrics import (
      5         media_metrics_collector)
      6 
      7 
      8 class 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