def test_cpu_usage(self, local_path):
        """
        Runs the video cpu usage test.

        @param local_path: the path to the video file.

        @return a dictionary that contains the test result.
        """
        def get_cpu_usage(cr):
            time.sleep(STABILIZATION_DURATION)
            cpu_usage_start = utils.get_cpu_usage()
            time.sleep(MEASUREMENT_DURATION)
            cpu_usage_end = utils.get_cpu_usage()
            return utils.compute_active_cpu_time(cpu_usage_start,
                                                 cpu_usage_end) * 100

        # crbug/753292 - APNG login pictures increase CPU usage. Move the more
        # strict idle checks after the login phase.
        utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT, CPU_IDLE_USAGE)
        utils.wait_for_cool_machine()
        if not utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT,
                                       CPU_IDLE_USAGE):
            logging.warning('Could not get idle CPU pre login.')
        if not utils.wait_for_cool_machine():
            logging.warning('Could not get cold machine pre login.')

        # Stop the thermal service that may change the cpu frequency.
        self._service_stopper = service_stopper.ServiceStopper(
            THERMAL_SERVICES)
        self._service_stopper.stop_services()
        # Set the scaling governor to performance mode to set the cpu to the
        # highest frequency available.
        self._original_governors = utils.set_high_performance_mode()
        return self.test_webrtc(local_path, get_cpu_usage)
    def test_cpu_usage(self, local_path):
        """
        Runs the video cpu usage test.

        @param local_path: the path to the video file.

        @return a dictionary that contains the test result.
        """
        def get_cpu_usage(cr):
            time.sleep(STABILIZATION_DURATION)
            cpu_usage_start = site_utils.get_cpu_usage()
            time.sleep(MEASUREMENT_DURATION)
            cpu_usage_end = site_utils.get_cpu_usage()
            return site_utils.compute_active_cpu_time(cpu_usage_start,
                                                      cpu_usage_end) * 100

        if not utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT,
                                       CPU_IDLE_USAGE):
            raise error.TestError('Could not get idle CPU.')
        if not utils.wait_for_cool_machine():
            raise error.TestError('Could not get cool machine.')
        # Stop the thermal service that may change the cpu frequency.
        services = service_stopper.ServiceStopper(THERMAL_SERVICES)
        services.stop_services()
        # Set the scaling governor to performance mode to set the cpu to the
        # highest frequency available.
        original_governors = utils.set_high_performance_mode()
        try:
            return self.test_webrtc(local_path, get_cpu_usage)
        finally:
            services.restore_services()
            utils.restore_scaling_governor_states(original_governors)
示例#3
0
    def test_playback(self, local_path, gather_result):
        """
        Runs the video playback test with and without hardware acceleration.

        @param local_path: the path to the video file.
        @param gather_result: a function to run and return the test result
                after chrome opens. The input parameter of the funciton is
                Autotest chrome instance.

        @return a dictionary that contains test the result.
        """
        keyvals = {}

        with chrome.Chrome(
                extra_browser_args=helper_logger.chrome_vmodule_flag(),
                arc_mode=self.arc_mode,
                init_network_controller=True) as cr:

            # crbug/753292 - enforce the idle checks after login
            if not utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT,
                                           CPU_IDLE_USAGE):
                logging.warning('Could not get idle CPU post login.')
            if not utils.wait_for_cool_machine():
                logging.warning('Could not get cold machine post login.')

            # Open the video playback page and start playing.
            self.start_playback(cr, local_path)
            result = gather_result(cr)

            # Check if decode is hardware accelerated.
            if histogram_verifier.is_bucket_present(
                    cr, constants.MEDIA_GVD_INIT_STATUS,
                    constants.MEDIA_GVD_BUCKET):
                keyvals[PLAYBACK_WITH_HW_ACCELERATION] = result
            else:
                logging.info("Can not use hardware decoding.")
                keyvals[PLAYBACK_WITHOUT_HW_ACCELERATION] = result
                return keyvals

        # Start chrome with disabled video hardware decode flag.
        with chrome.Chrome(extra_browser_args=
                           DISABLE_ACCELERATED_VIDEO_DECODE_BROWSER_ARGS,
                           arc_mode=self.arc_mode,
                           init_network_controller=True) as cr:
            # Open the video playback page and start playing.
            self.start_playback(cr, local_path)
            result = gather_result(cr)

            # Make sure decode is not hardware accelerated.
            if histogram_verifier.is_bucket_present(
                    cr, constants.MEDIA_GVD_INIT_STATUS,
                    constants.MEDIA_GVD_BUCKET):
                raise error.TestError(
                    'Video decode acceleration should not be working.')
            keyvals[PLAYBACK_WITHOUT_HW_ACCELERATION] = result

        return keyvals
示例#4
0
    def run_once(self,
                 test_duration_secs=30,
                 test_setting_num_fishes=(50, 1000),
                 power_test=False,
                 ac_ok=False,
                 memory_pressure=None):
        """Find a browser with telemetry, and run the test.

        @param test_duration_secs: The duration in seconds to run each scenario
                for.
        @param test_setting_num_fishes: A list of the numbers of fishes to
                enable in the test.
        @param power_test: Boolean on whether to run power_test
        @param ac_ok: Boolean on whether its ok to have AC power supplied.
        @param memory_pressure: A dictionay which specifies memory pressure
                parameters:
                'consumer_mode': 'single' or 'multiple' to have one or moultiple
                concurrent memory consumers.
                'consumer_size_mb': Amount of memory to allocate. In 'single'
                mode, a single memory consumer would allocate memory by the
                specific size. It then gradually allocates more memory until
                FPS down to near 0. In 'multiple' mode, memory consumers of
                this size would be spawn one by one until FPS down to near 0.
                'memory_to_reserve_mb': Amount of memory to reserve before
                running memory consumer. In practical we allocate mlocked
                memory (i.e., not swappable) to consume free memory until this
                amount of free memory remained.
        """
        self.test_duration_secs = test_duration_secs
        self.test_setting_num_fishes = test_setting_num_fishes

        with chrome.Chrome(logged_in=False, init_network_controller=True) as cr:
            cr.browser.platform.SetHTTPServerDirectories(self.srcdir)
            test_url = cr.browser.platform.http_server.UrlOf(
                os.path.join(self.srcdir, 'aquarium.html'))

            if not utils.wait_for_idle_cpu(60.0, 0.1):
                if not utils.wait_for_idle_cpu(20.0, 0.2):
                    raise error.TestFail('Failed: Could not get idle CPU.')
            if not utils.wait_for_cool_machine():
               raise error.TestFail('Failed: Could not get cold machine.')
            if memory_pressure:
                self.run_fish_test_with_memory_pressure(
                    cr.browser, test_url, num_fishes=1000,
                    memory_pressure=memory_pressure)
                self.tear_down_webpage()
            elif power_test:
                self._test_power = True
                self.run_power_test(cr.browser, test_url, ac_ok)
                self.tear_down_webpage()
            else:
                for n in self.test_setting_num_fishes:
                    self.run_fish_test(cr.browser, test_url, n)
                    self.tear_down_webpage()
        self.write_perf_keyval(self.perf_keyval)
    def run_once(self):
        available_freqs = []
        # When the Intel P-state driver is used, the driver implements an
        # internal governer which selects the currect P-state automatically.
        # Any value between cpuinfo_min_freq and cpuinfo_max_freq is allowed
        # for scaling_max_freq and scaling_min_freq. Setting them is
        # equivalent to setting max_perf_pct and min_perf_pct under
        # /sys/devices/system/cpu/intel_pstate/.
        f = open(self.sys_cpufreq_path + 'scaling_driver', 'r')
        if ('intel_pstate\n' == f.read()):
            fmin = open(self.sys_cpufreq_path + 'cpuinfo_min_freq', 'r')
            fmax = open(self.sys_cpufreq_path + 'cpuinfo_max_freq', 'r')
            available_freqs = map(int, [fmin.read(), fmax.read()])
            fmin.close()
            fmax.close()

            # generate a list of frequencies between min and max
            step = (available_freqs[1] - available_freqs[0]) / 4
            if step:
                available_freqs = range(available_freqs[0],
                                        available_freqs[1] + 1, step)
        f.close()

        if not available_freqs:
            f = open(self.sys_cpufreq_path + 'scaling_available_frequencies',
                     'r')
            available_freqs = sorted(map(int, f.readline().split()))
            f.close()

        # exit if there are not at least two frequencies
        if (len(available_freqs) < 2):
            return

        # get current maximum scaling frequency
        f = open(self.sys_cpufreq_path + 'scaling_max_freq', 'r')
        max_freq = int(f.readline())
        f.close()

        if max_freq < available_freqs[-1]:
            logging.info(
                'Current maximum frequency %d is lower than available maximum %d',
                max_freq, available_freqs[-1])
            # Board is probably thermally throttled
            if not utils.wait_for_cool_machine():
                raise error.TestFail('Could not get cold machine.')

        # set max to 2nd to highest frequency, then the highest
        self._test_freq_set(available_freqs[-2:], 'scaling_max_freq')

        # set to min 2nd to lowest frequency, then the lowest
        self._test_freq_set(reversed(available_freqs[:2]), 'scaling_min_freq')
    def __enter__(self):
        # Stop the thermal service that may change the cpu frequency.
        self._service_stopper = service_stopper.ServiceStopper(THERMAL_SERVICES)
        self._service_stopper.stop_services()

        if not utils.wait_for_idle_cpu(
                WAIT_FOR_IDLE_CPU_TIMEOUT, CPU_IDLE_USAGE):
            raise error.TestError('Could not get idle CPU.')
        if not utils.wait_for_cool_machine():
            raise error.TestError('Could not get cold machine.')

        # Set the scaling governor to performance mode to set the cpu to the
        # highest frequency available.
        self._original_governors = utils.set_high_performance_mode()
        return self
示例#7
0
 def __init__(self):
     self._service_stopper = None
     # Keep a copy of the current state for cleanup.
     self._temperature_init = utils.get_current_temperature_max()
     self._temperature_critical = utils.get_temperature_critical()
     self._original_governors = utils.set_high_performance_mode()
     self._error_reason = None
     if not utils.wait_for_idle_cpu(60.0, 0.1):
         self._error_reason = 'Could not get idle CPU.'
         return
     if not utils.wait_for_cool_machine():
         self._error_reason = 'Could not get cold machine.'
         return
     self._temperature_cold = utils.get_current_temperature_max()
     self._temperature_max = self._temperature_cold
     threading.Thread(target=self._monitor_performance_state).start()
     # Should be last just in case we had a runaway process.
     self._stop_thermal_throttling()
    def run_once(self,
                 test_duration_secs=30,
                 test_setting_num_fishes=(50, 1000),
                 power_test=False,
                 ac_ok=False):
        """Find a browser with telemetry, and run the test.

        @param test_duration_secs: The duration in seconds to run each scenario
                for.
        @param test_setting_num_fishes: A list of the numbers of fishes to
                enable in the test.
        @param power_test: Boolean on whether to run power_test
        @param ac_ok: Boolean on whether its ok to have AC power supplied.
        """
        self.test_duration_secs = test_duration_secs
        self.test_setting_num_fishes = test_setting_num_fishes

        with chrome.Chrome(logged_in=False,
                           init_network_controller=True) as cr:
            cr.browser.platform.SetHTTPServerDirectories(self.srcdir)
            test_url = cr.browser.platform.http_server.UrlOf(
                os.path.join(self.srcdir, 'aquarium.html'))

            if not utils.wait_for_idle_cpu(60.0, 0.1):
                if not utils.wait_for_idle_cpu(20.0, 0.2):
                    raise error.TestFail('Failed: Could not get idle CPU.')
            if not utils.wait_for_cool_machine():
                raise error.TestFail('Failed: Could not get cold machine.')
            if power_test:
                self._test_power = True
                self.run_power_test(cr.browser, test_url, ac_ok)
                with self.sampler_lock:
                    self.active_tab.Close()
                    self.active_tab = None
            else:
                for n in self.test_setting_num_fishes:
                    self.run_fish_test(cr.browser, test_url, n)
                    # Do not close the tab when the sampler_callback is
                    # doing his work.
                    with self.sampler_lock:
                        self.active_tab.Close()
                        self.active_tab = None
        self.write_perf_keyval(self.perf_keyval)
    def run_once(self, size='800x600', hasty=False, min_score=None):
        dep = 'glmark2'
        dep_dir = os.path.join(self.autodir, 'deps', dep)
        self.job.install_pkg(dep, 'dep', dep_dir)

        glmark2 = os.path.join(self.autodir, 'deps/glmark2/glmark2')
        if not os.path.exists(glmark2):
            raise error.TestFail('Could not find test binary. Setup error.')

        glmark2_data = os.path.join(self.autodir, 'deps/glmark2/data')

        options = []
        options.append('--data-path %s' % glmark2_data)
        options.append('--size %s' % size)
        options.append('--annotate')
        if hasty:
            options.append('-b :duration=0.2')
        else:
            options.append('-b :duration=2')
        cmd = glmark2 + ' ' + ' '.join(options)
        if not utils.is_freon():
            cmd = 'X :1 vt1 & sleep 1; chvt 1 && DISPLAY=:1 ' + cmd

        if os.environ.get('CROS_FACTORY'):
            from autotest_lib.client.cros import factory_setup_modules
            from cros.factory.test import ui
            ui.start_reposition_thread('^glmark')

        # TODO(ihf): Switch this test to use perf.PerfControl like
        #            graphics_GLBench once it is stable. crbug.com/344766.
        if not hasty:
            if not utils.wait_for_idle_cpu(60.0, 0.1):
                if not utils.wait_for_idle_cpu(20.0, 0.2):
                    raise error.TestFail('Could not get idle CPU.')
            if not utils.wait_for_cool_machine():
                raise error.TestFail('Could not get cold machine.')

        try:
            result = utils.run(cmd,
                               stderr_is_expected=False,
                               stdout_tee=utils.TEE_TO_LOGS,
                               stderr_tee=utils.TEE_TO_LOGS)
        finally:
            # Just sending SIGTERM to X is not enough; we must wait for it to
            # really die before we start a new X server (ie start ui).
            if not utils.is_freon():
                utils.ensure_processes_are_dead_by_name('^X$')

        logging.info(result)
        for line in result.stderr.splitlines():
            if line.startswith('Error:'):
                raise error.TestFail(line)

        # Numbers in hasty mode are not as reliable, so don't send them to
        # the dashboard etc.
        if not hasty:
            keyvals = {}
            score = None
            test_re = re.compile(GLMARK2_TEST_RE)
            for line in result.stdout.splitlines():
                match = test_re.match(line)
                if match:
                    test = '%s.%s' % (match.group('scene'),
                                      match.group('options'))
                    test = test.translate(description_table,
                                          description_delete)
                    frame_time = match.group('frametime')
                    keyvals[test] = frame_time
                    self.output_perf_value(description=test,
                                           value=frame_time,
                                           units='ms',
                                           higher_is_better=False)
                else:
                    # glmark2 output the final performance score as:
                    #  glmark2 Score: 530
                    match = re.findall(GLMARK2_SCORE_RE, line)
                    if match:
                        score = int(match[0])
            if score is None:
                raise error.TestFail('Unable to read benchmark score')
            # Output numbers for plotting by harness.
            logging.info('GLMark2 score: %d', score)
            if os.environ.get('CROS_FACTORY'):
                from autotest_lib.client.cros import factory_setup_modules
                from cros.factory.event_log import EventLog
                EventLog('graphics_GLMark2').Log('glmark2_score', score=score)
            keyvals['glmark2_score'] = score
            self.write_perf_keyval(keyvals)
            self.output_perf_value(description='Score',
                                   value=score,
                                   units='score',
                                   higher_is_better=True)

            if min_score is not None and score < min_score:
                raise error.TestFail('Benchmark score %d < %d (minimum score '
                                     'requirement)' % (score, min_score))
 def wait_for_idle_cpu(self):
     if not utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT,
                                    CPU_IDLE_USAGE):
         logging.warning('Could not get idle CPU post login.')
     if not utils.wait_for_cool_machine():
         logging.warning('Could not get cold machine post login.')
    def test_webrtc(self, local_path, gather_result):
        """
        Runs the webrtc test with and without hardware acceleration.

        @param local_path: the path to the video file.
        @param gather_result: a function to run and return the test result
                after chrome opens. The input parameter of the funciton is
                Autotest chrome instance.

        @return a dictionary that contains test the result.
        """
        keyvals = {}
        EXTRA_BROWSER_ARGS.append(FAKE_FILE_ARG % local_path)

        with chrome.Chrome(extra_browser_args=EXTRA_BROWSER_ARGS +\
                           [helper_logger.chrome_vmodule_flag()],
                           arc_mode=self.arc_mode,
                           init_network_controller=True) as cr:
            # On daisy, Chrome freezes about 30 seconds after login because of
            # TPM error. See http://crbug.com/588579.
            if utils.get_board() == 'daisy':
                logging.warning('Delay 30s for issue 588579 on daisy')
                time.sleep(30)
            # Open WebRTC loopback page and start the loopback.
            self.start_loopback(cr)
            result = gather_result(cr)

            # Check if decode is hardware accelerated.
            if histogram_verifier.is_bucket_present(
                    cr, constants.RTC_INIT_HISTOGRAM,
                    constants.RTC_VIDEO_INIT_BUCKET):
                keyvals[WEBRTC_WITH_HW_ACCELERATION] = result
            else:
                logging.info("Can not use hardware decoding.")
                keyvals[WEBRTC_WITHOUT_HW_ACCELERATION] = result
                return keyvals

        # Start chrome with disabled video hardware decode flag.
        with chrome.Chrome(
                extra_browser_args=DISABLE_ACCELERATED_VIDEO_DECODE_BROWSER_ARGS
                + EXTRA_BROWSER_ARGS,
                arc_mode=self.arc_mode,
                init_network_controller=True) as cr:

            # crbug/753292 - enforce the idle checks after login
            if not utils.wait_for_idle_cpu(WAIT_FOR_IDLE_CPU_TIMEOUT,
                                           CPU_IDLE_USAGE):
                logging.warning('Could not get idle CPU post login.')
            if not utils.wait_for_cool_machine():
                logging.warning('Could not get cold machine post login.')

            if utils.get_board() == 'daisy':
                logging.warning('Delay 30s for issue 588579 on daisy')
                time.sleep(30)
            # Open the webrtc loopback page and start the loopback.
            self.start_loopback(cr)
            result = gather_result(cr)

            # Make sure decode is not hardware accelerated.
            if histogram_verifier.is_bucket_present(
                    cr, constants.RTC_INIT_HISTOGRAM,
                    constants.RTC_VIDEO_INIT_BUCKET):
                raise error.TestError('HW decode should not be used.')
            keyvals[WEBRTC_WITHOUT_HW_ACCELERATION] = result

        return keyvals
    def run_once(self, size='800x600', hasty=False, min_score=None):
        dep = 'glmark2'
        dep_dir = os.path.join(self.autodir, 'deps', dep)
        self.job.install_pkg(dep, 'dep', dep_dir)

        glmark2 = os.path.join(self.autodir, 'deps/glmark2/glmark2')
        if not os.path.exists(glmark2):
            raise error.TestFail('Failed: Could not find test binary.')

        glmark2_data = os.path.join(self.autodir, 'deps/glmark2/data')

        options = []
        options.append('--data-path %s' % glmark2_data)
        options.append('--size %s' % size)
        options.append('--annotate')
        if hasty:
            options.append('-b :duration=0.2')
        else:
            options.append('-b :duration=2')
        cmd = glmark2 + ' ' + ' '.join(options)

        if os.environ.get('CROS_FACTORY'):
            from autotest_lib.client.cros import factory_setup_modules
            from cros.factory.test import ui
            ui.start_reposition_thread('^glmark')

        # TODO(ihf): Switch this test to use perf.PerfControl like
        #            graphics_GLBench once it is stable. crbug.com/344766.
        if not hasty:
            if not utils.wait_for_idle_cpu(60.0, 0.1):
                if not utils.wait_for_idle_cpu(20.0, 0.2):
                    raise error.TestFail('Failed: Could not get idle CPU.')
            if not utils.wait_for_cool_machine():
                raise error.TestFail('Failed: Could not get cold machine.')

        # In this test we are manually handling stderr, so expected=True.
        # Strangely autotest takes CmdError/CmdTimeoutError as warning only.
        try:
            result = utils.run(cmd,
                               stderr_is_expected=True,
                               stdout_tee=utils.TEE_TO_LOGS,
                               stderr_tee=utils.TEE_TO_LOGS)
        except error.CmdError:
            raise error.TestFail('Failed: CmdError running %s' % cmd)
        except error.CmdTimeoutError:
            raise error.TestFail('Failed: CmdTimeout running %s' % cmd)

        logging.info(result)
        for line in result.stderr.splitlines():
            if line.startswith('Error:'):
                # Line already starts with 'Error: ", not need to prepend.
                raise error.TestFail(line)

        # Numbers in hasty mode are not as reliable, so don't send them to
        # the dashboard etc.
        if not hasty:
            keyvals = {}
            score = None
            # glmark2 output the final performance score as:
            #  glmark2 Score: 530
            for line in result.stdout.splitlines():
                match = re.findall(GLMARK2_SCORE_RE, line)
                if match:
                    score = int(match[0])
            if not score:
                raise error.TestFail('Failed: Unable to read benchmark score')
            # Output numbers for plotting by harness.
            logging.info('GLMark2 score: %d', score)
            if os.environ.get('CROS_FACTORY'):
                from autotest_lib.client.cros import factory_setup_modules
                from cros.factory.event_log import EventLog
                EventLog('graphics_GLMark2').Log('glmark2_score', score=score)
            keyvals['glmark2_score'] = score
            self.write_perf_keyval(keyvals)
            self.output_perf_value(description='Score',
                                   value=score,
                                   units='score',
                                   higher_is_better=True)

            if min_score is not None and score < min_score:
                raise error.TestFail(
                    'Failed: Benchmark score %d < %d (minimum score '
                    'requirement)' % (score, min_score))
    def run_once(self, video_url, video_short_name):
        """Runs the graphics_VideoRenderingPower test.

        @param video_url: URL with autoplay video inside. It's assumed that
                 there's just one <video> in the HTML, and that it fits in the
                 viewport.
        @param video_short_name: short string describing the video; itt will be
                 presented as part of the dashboard entry name.
        """

        # TODO(mcasas): Extend this test to non-Intel platforms.
        if not power_utils.has_rapl_support():
            logging.warning(
                'This board has no RAPL power measurement support, '
                'skipping test.')
            return

        rapl = []
        if power_utils.has_battery():
            rapl.append(
                power_status.SystemPower(self._power_status.battery_path))
        else:
            logging.warning('This board has no battery.')
        rapl += power_rapl.create_rapl()

        for test_name_and_flags in TEST_NAME_AND_FLAGS:
            logging.info('Test case: %s', test_name_and_flags[0])
            # Launch Chrome with the appropriate flag combination.
            with chrome.Chrome(extra_browser_args=test_name_and_flags[1],
                               init_network_controller=True) as cr:

                if not utils.wait_for_idle_cpu(IDLE_CPU_WAIT_TIMEOUT_SECONDS,
                                               IDLE_CPU_LOAD_PERCENTAGE):
                    raise error.TestFail('Failed: Could not get idle CPU.')
                if not utils.wait_for_cool_machine():
                    raise error.TestFail('Failed: Could not get cold machine.')

                tab = cr.browser.tabs[0]
                tab.Navigate(video_url)
                tab.WaitForDocumentReadyStateToBeComplete()
                tab.EvaluateJavaScript(
                    'document.'
                    'getElementsByTagName(\'video\')[0].scrollIntoView(true)')

                # Disabling hardware overlays is difficult because the flag is
                # already in the browser. Instead, scroll a bit down to make the
                # video bleed out of the viewport.
                if '--enable-hardware-overlays=' in test_name_and_flags[1]:
                    tab.EvaluateJavaScript('window.scrollBy(0, 1)')

                power_logger = power_status.PowerLogger(rapl)
                power_logger.start()
                time.sleep(PREAMBLE_DURATION_SECONDS)

                start_time = time.time()
                time.sleep(MEASUREMENT_DURATION_SECONDS)
                power_logger.checkpoint('result', start_time)

                measurements = power_logger.calc()
                logging.debug(measurements)

                for category in sorted(measurements):
                    if category.endswith('_pwr'):
                        description = '%s_%s_%s' % (
                            video_short_name, test_name_and_flags[0], category)
                        self.output_perf_value(description=description,
                                               value=measurements[category],
                                               units='W',
                                               higher_is_better=False,
                                               graph=GRAPH_NAME)

                    if category.endswith('_pwr_avg'):
                        # write_perf_keyval() wants units (W) first in lowercase.
                        description = '%s_%s_%s' % (
                            video_short_name, test_name_and_flags[0], category)
                        self.write_perf_keyval(
                            {'w_' + description: measurements[category]})