1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
7 from metrics import Metric
8 from telemetry.core.platform import factory
11 class PowerMetric(Metric):
12 """A metric for measuring power usage."""
17 super(PowerMetric, self).__init__()
20 self._starting_cpu_stats = None
24 # TODO(jeremy): Remove once crbug.com/350841 is fixed.
25 # Don't leave power monitoring processes running on the system.
27 parent = super(PowerMetric, self)
28 if hasattr(parent, '__del__'):
31 def _StopInternal(self):
32 """ Stop monitoring power if measurement is running. This function is
37 self._results = self._browser.platform.StopMonitoringPower()
38 if self._results: # StopMonitoringPower() can return None.
39 self._results['cpu_stats'] = (
40 _SubtractCpuStats(self._browser.cpu_stats, self._starting_cpu_stats))
43 def CustomizeBrowserOptions(cls, options):
44 PowerMetric.enabled = options.report_root_metrics
46 # Friendly informational messages if measurement won't run.
47 system_supports_power_monitoring = (
48 factory.GetPlatformBackendForCurrentOS().CanMonitorPower())
49 if system_supports_power_monitoring:
50 if not PowerMetric.enabled:
52 "--report-root-metrics omitted, power measurement disabled.")
54 logging.info("System doesn't support power monitoring, power measurement"
57 def Start(self, _, tab):
58 if not PowerMetric.enabled:
61 if not tab.browser.platform.CanMonitorPower():
65 self._browser = tab.browser
68 # This line invokes top a few times, call before starting power measurement.
69 self._starting_cpu_stats = self._browser.cpu_stats
70 self._browser.platform.StartMonitoringPower(self._browser)
73 def Stop(self, _, tab):
74 if not PowerMetric.enabled:
77 if not tab.browser.platform.CanMonitorPower():
82 def AddResults(self, _, results):
83 """Add the collected power data into the results object.
85 This function needs to be robust in the face of differing power data on
86 various platforms. Therefore data existence needs to be checked when
87 building up the results. Additionally 0 is a valid value for many of the
88 metrics here which is why there are plenty of checks for 'is not None'
94 energy_consumption_mwh = self._results.get('energy_consumption_mwh')
95 if energy_consumption_mwh is not None:
96 results.Add('energy_consumption_mwh', 'mWh', energy_consumption_mwh)
98 component_utilization = self._results.get('component_utilization', {})
100 gpu_power = component_utilization.get('gpu', {})
101 gpu_freq_hz = gpu_power.get('average_frequency_hz')
102 if gpu_freq_hz is not None:
103 results.Add('gpu_average_frequency_hz', 'hz', gpu_freq_hz)
105 # Add idle wakeup numbers for all processes.
106 for (process_type, stats) in self._results.get('cpu_stats', {}).items():
107 trace_name_for_process = 'idle_wakeups_%s' % (process_type.lower())
108 results.Add(trace_name_for_process, 'count', stats)
110 # Add temperature measurements.
111 whole_package_utilization = component_utilization.get('whole_package', {})
112 board_temperature_c = whole_package_utilization.get('average_temperature_c')
113 if board_temperature_c is not None:
114 results.Add('board_temperature', 'celsius', board_temperature_c)
118 def _SubtractCpuStats(cpu_stats, start_cpu_stats):
119 """Computes number of idle wakeups that occurred over measurement period.
121 Each of the two cpu_stats arguments is a dict as returned by the
122 Browser.cpu_stats call.
125 A dict of process type names (Browser, Renderer, etc.) to idle wakeup count
126 over the period recorded by the input.
129 for process_type in cpu_stats:
130 assert process_type in start_cpu_stats, 'Mismatching process types'
131 # Skip any process_types that are empty.
132 if (not cpu_stats[process_type]) or (not start_cpu_stats[process_type]):
134 # Skip if IdleWakeupCount is not present.
135 if (('IdleWakeupCount' not in cpu_stats[process_type]) or
136 ('IdleWakeupCount' not in start_cpu_stats[process_type])):
138 idle_wakeup_delta = (cpu_stats[process_type]['IdleWakeupCount'] -
139 start_cpu_stats[process_type]['IdleWakeupCount'])
140 cpu_delta[process_type] = idle_wakeup_delta