普通文本  |  172行  |  6.15 KB

# Copyright (c) 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import json, numpy, os, time, urllib, urllib2

from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import lsbrelease_utils
from autotest_lib.client.cros.power import power_status
from autotest_lib.client.cros.power import power_utils


class BaseDashboard(object):
    """Base class that implements method for prepare and upload data to power
    dashboard.
    """

    def __init__(self, logger, testname, resultsdir=None, uploadurl=None):
        """Create BaseDashboard objects

        Args:
            logger: object that store the log. This will get convert to
                    dictionary by self._convert()
            testname: name of current test
            resultsdir: directory to save the power json
            uploadurl: url to upload power data
        """
        self._logger = logger
        self._testname = testname
        self._resultsdir = resultsdir
        self._uploadurl = uploadurl


    def _create_powerlog_dict(self, raw_measurement):
        """Create powerlog dictionary from raw measurement data
        Data format in go/power-dashboard-data

        Args:
            raw_measurement: dictionary contains raw measurement data.

        Returns:
            A dictionary of powerlog.
        """
        powerlog_dict = {
            'format_version': 2,
            'timestamp': time.time(),
            'test': self._testname,
            'dut': {
                'board': utils.get_board(),
                'version': {
                    'hw': utils.get_hardware_revision(),
                    'milestone':
                            lsbrelease_utils.get_chromeos_release_milestone(),
                    'os': lsbrelease_utils.get_chromeos_release_version(),
                    'channel': lsbrelease_utils.get_chromeos_channel(),
                    'firmware': utils.get_firmware_version(),
                    'ec': utils.get_ec_version(),
                    'kernel': utils.get_kernel_version(),
                },
                'sku' : {
                    'cpu': utils.get_cpu_name(),
                    'memory_size': utils.get_mem_total_gb(),
                    'storage_size':
                            utils.get_disk_size_gb(utils.get_root_device()),
                    'display_resolution': utils.get_screen_resolution(),
                },
                'ina': {
                    'version': 0,
                    'ina': raw_measurement['data'].keys()
                },
                'note': ''
            },
            'power': raw_measurement
        }

        if power_utils.has_battery():
            # Round the battery size to nearest tenth because it is fluctuated
            # for platform without battery norminal voltage data.
            powerlog_dict['dut']['sku']['battery_size'] = round(
                    power_status.get_status().battery[0].energy_full_design, 1)
            powerlog_dict['dut']['sku']['battery_shutdown_percent'] = \
                    power_utils.get_low_battery_shutdown_percent()
        return powerlog_dict


    def _save_json(self, powerlog_dict, resultsdir, filename='power_log.json'):
        """Convert powerlog dict to human readable formatted JSON and
        save to <resultsdir>/<filename>

        Args:
            powerlog_dict: dictionary of power data
            resultsdir: directory to save formatted JSON object
            filename: filename to save
        """
        filename = os.path.join(resultsdir, filename)
        with file(filename, 'w') as f:
            json.dump(powerlog_dict, f, indent=4, separators=(',', ': '))


    def _upload(self, powerlog_dict, uploadurl):
        """Convert powerlog dict to minimal size JSON and upload to dashboard.

        Args:
            powerlog_dict: dictionary of power data
        """
        data_obj = {'data': json.dumps(powerlog_dict)}
        encoded = urllib.urlencode(data_obj)
        req = urllib2.Request(uploadurl, encoded)
        urllib2.urlopen(req)


    def _convert(self):
        """Convert data from self._logger object to raw power measurement
        dictionary.

        MUST be implemented in subclass

        Return:
            raw measurement dictionary
        """
        raise NotImplementedError

    def upload(self):
        """Upload powerlog to dashboard and save data to results directory.
        """
        raw_measurement = self._convert()
        powerlog_dict = self._create_powerlog_dict(raw_measurement)
        if self._resultsdir is not None:
            self._save_json(powerlog_dict, self._resultsdir)
        if self._uploadurl is not None:
            self._upload(powerlog_dict, self._uploadurl)


class MeasurementLoggerDashboard(BaseDashboard):
    """Dashboard class for power_status.MeasurementLogger
    """

    def _convert(self):
        """Convert data from power_status.MeasurementLogger object to raw
        power measurement dictionary.

        Return:
            raw measurement dictionary
        """
        power_dict = {
            'sample_count': len(self._logger.readings),
            'sample_duration': 0,
            'average': dict(),
            'data': dict()
        }
        if power_dict['sample_count'] > 1:
            total_duration = self._logger.times[-1] - self._logger.times[0]
            power_dict['sample_duration'] = \
                    1.0 * total_duration / (power_dict['sample_count'] - 1)

        for i, domain_readings in enumerate(zip(*self._logger.readings)):
            domain = self._logger.domains[i]
            power_dict['data'][domain] = domain_readings
            power_dict['average'][domain] = numpy.average(domain_readings)
        return power_dict


class PowerLoggerDashboard(MeasurementLoggerDashboard):
    """Dashboard class for power_status.PowerLogger
    """

    def __init__(self, logger, testname, resultsdir=None, uploadurl=None):
        if uploadurl is None:
            uploadurl = 'http://chrome-power.appspot.com/rapl'
        super(PowerLoggerDashboard, self).__init__(logger, testname, resultsdir,
                                                   uploadurl)