# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import logging
+import time
from metrics import Metric
-from telemetry.core.platform import factory
+from telemetry.value import scalar
class PowerMetric(Metric):
"""A metric for measuring power usage."""
- enabled = True
+ # System power draw while idle.
+ _quiescent_power_draw_mwh = 0
- def __init__(self):
+ def __init__(self, browser, quiescent_measurement_time_s=0):
+ """PowerMetric Constructor.
+
+ Args:
+ browser: browser object to use.
+ quiescent_measurement_time_s: time to measure quiescent power,
+ in seconds. 0 means don't measure quiescent power."""
super(PowerMetric, self).__init__()
- self._browser = None
+ self._browser = browser
self._running = False
self._starting_cpu_stats = None
self._results = None
+ self._MeasureQuiescentPower(quiescent_measurement_time_s)
def __del__(self):
# TODO(jeremy): Remove once crbug.com/350841 is fixed.
parent.__del__()
def _StopInternal(self):
- """ Stop monitoring power if measurement is running. This function is
+ """Stop monitoring power if measurement is running. This function is
idempotent."""
if not self._running:
return
self._results['cpu_stats'] = (
_SubtractCpuStats(self._browser.cpu_stats, self._starting_cpu_stats))
- @classmethod
- def CustomizeBrowserOptions(cls, options):
- PowerMetric.enabled = options.report_root_metrics
-
- # Friendly informational messages if measurement won't run.
- system_supports_power_monitoring = (
- factory.GetPlatformBackendForCurrentOS().CanMonitorPower())
- if system_supports_power_monitoring:
- if not PowerMetric.enabled:
- logging.warning(
- "--report-root-metrics omitted, power measurement disabled.")
- else:
- logging.info("System doesn't support power monitoring, power measurement"
- " disabled.")
+ def _MeasureQuiescentPower(self, measurement_time_s):
+ """Measure quiescent power draw for the system."""
+ platform = self._browser.platform
+ if not platform.CanMonitorPower() or \
+ platform.CanMeasurePerApplicationPower() or \
+ not measurement_time_s:
+ return
- def Start(self, _, tab):
- if not PowerMetric.enabled:
+ # Only perform quiescent measurement once per run.
+ if PowerMetric._quiescent_power_draw_mwh:
return
+ platform.StartMonitoringPower(self._browser)
+ time.sleep(measurement_time_s)
+ power_results = platform.StopMonitoringPower()
+ PowerMetric._quiescent_power_draw_mwh = (
+ power_results.get('energy_consumption_mwh', 0))
+
+ def Start(self, _, tab):
if not tab.browser.platform.CanMonitorPower():
return
self._results = None
- self._browser = tab.browser
self._StopInternal()
# This line invokes top a few times, call before starting power measurement.
self._running = True
def Stop(self, _, tab):
- if not PowerMetric.enabled:
- return
-
if not tab.browser.platform.CanMonitorPower():
return
if not self._results:
return
- energy_consumption_mwh = self._results.get('energy_consumption_mwh')
- if energy_consumption_mwh is not None:
- results.Add('energy_consumption_mwh', 'mWh', energy_consumption_mwh)
+ application_energy_consumption_mwh = (
+ self._results.get('application_energy_consumption_mwh'))
+ total_energy_consumption_mwh = self._results.get('energy_consumption_mwh')
+
+ if not application_energy_consumption_mwh and total_energy_consumption_mwh:
+ application_energy_consumption_mwh = max(
+ total_energy_consumption_mwh - PowerMetric._quiescent_power_draw_mwh,
+ 0)
+
+ if total_energy_consumption_mwh is not None:
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'energy_consumption_mwh', 'mWh',
+ total_energy_consumption_mwh))
+
+ if application_energy_consumption_mwh is not None:
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'application_energy_consumption_mwh', 'mWh',
+ application_energy_consumption_mwh))
component_utilization = self._results.get('component_utilization', {})
# GPU Frequency.
gpu_power = component_utilization.get('gpu', {})
gpu_freq_hz = gpu_power.get('average_frequency_hz')
if gpu_freq_hz is not None:
- results.Add('gpu_average_frequency_hz', 'hz', gpu_freq_hz)
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'gpu_average_frequency_hz', 'hz', gpu_freq_hz,
+ important=False))
# Add idle wakeup numbers for all processes.
for (process_type, stats) in self._results.get('cpu_stats', {}).items():
trace_name_for_process = 'idle_wakeups_%s' % (process_type.lower())
- results.Add(trace_name_for_process, 'count', stats)
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, trace_name_for_process, 'count', stats,
+ important=False))
# Add temperature measurements.
whole_package_utilization = component_utilization.get('whole_package', {})
board_temperature_c = whole_package_utilization.get('average_temperature_c')
if board_temperature_c is not None:
- results.Add('board_temperature', 'celsius', board_temperature_c)
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'board_temperature', 'celsius',
+ board_temperature_c, important=False))
self._results = None