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.
9 from telemetry import decorators
10 from telemetry.core.platform import power_monitor
13 MSR_RAPL_POWER_UNIT = 0x606
14 MSR_PKG_ENERGY_STATUS = 0x611 # Whole package
15 MSR_PP0_ENERGY_STATUS = 0x639 # Core
16 MSR_PP1_ENERGY_STATUS = 0x641 # Uncore
17 MSR_DRAM_ENERGY_STATUS = 0x619
18 IA32_PACKAGE_THERM_STATUS = 0x1b1
19 IA32_TEMPERATURE_TARGET = 0x1a2
22 def _JoulesToMilliwattHours(value_joules):
23 return value_joules * 1000 / 3600.
26 def _IsSandyBridgeOrLater(vendor, family, model):
28 # https://software.intel.com/en-us/articles/intel-architecture-and- \
29 # processor-identification-with-cpuid-model-and-family-numbers
30 # http://www.speedtraq.com
31 return ('Intel' in vendor and family == 6 and
32 (model in (0x2A, 0x2D) or model >= 0x30))
39 cpuinfo = open('/proc/cpuinfo').read().splitlines()
41 if vendor and family and model:
43 if line.startswith('vendor_id'):
44 vendor = line.split('\t')[1]
45 elif line.startswith('cpu family'):
46 family = int(line.split(' ')[2])
47 elif line.startswith('model\t\t'):
48 model = int(line.split(' ')[1])
49 if not _IsSandyBridgeOrLater(vendor, family, model):
50 logging.info('Cannot monitor power: pre-Sandy Bridge CPU.')
55 class MsrPowerMonitor(power_monitor.PowerMonitor):
56 def __init__(self, backend):
57 super(MsrPowerMonitor, self).__init__()
58 self._backend = backend
59 self._start_energy_j = None
60 self._start_temp_c = None
62 def CanMonitorPower(self):
63 if self._backend.GetOSName() == 'win':
64 return self._WinCanMonitorPower()
65 elif self._backend.GetOSName() == 'linux':
66 return self._LinuxCanMonitorPower()
69 def StartMonitoringPower(self, browser):
70 assert self._start_energy_j is None and self._start_temp_c is None, (
71 'Called StartMonitoringPower() twice.')
72 self._start_energy_j = self._PackageEnergyJoules()
73 self._start_temp_c = self._TemperatureCelsius()
75 def StopMonitoringPower(self):
76 assert not(self._start_energy_j is None or self._start_temp_c is None), (
77 'Called StopMonitoringPower() before StartMonitoringPower().')
79 energy_consumption_j = self._PackageEnergyJoules() - self._start_energy_j
80 average_temp_c = (self._TemperatureCelsius() + self._start_temp_c) / 2.
81 if energy_consumption_j < 0: # Correct overflow.
82 # The energy portion of the MSR is 4 bytes.
83 energy_consumption_j += 2 ** 32 * self._EnergyMultiplier()
85 self._start_energy_j = None
86 self._start_temp_c = None
90 'energy_consumption_mwh': _JoulesToMilliwattHours(energy_consumption_j),
91 'component_utilization': {
93 'average_temperature_c': average_temp_c,
99 def _EnergyMultiplier(self):
100 return 0.5 ** self._backend.ReadMsr(MSR_RAPL_POWER_UNIT, 8, 5)
102 def _PackageEnergyJoules(self):
103 return (self._backend.ReadMsr(MSR_PKG_ENERGY_STATUS, 0, 32) *
104 self._EnergyMultiplier())
106 def _TemperatureCelsius(self):
107 tcc_activation_temp = self._backend.ReadMsr(IA32_TEMPERATURE_TARGET, 16, 7)
108 if tcc_activation_temp <= 0:
109 tcc_activation_temp = 105
110 package_temp_headroom = self._backend.ReadMsr(
111 IA32_PACKAGE_THERM_STATUS, 16, 7)
112 return tcc_activation_temp - package_temp_headroom
114 def _CheckMSRs(self):
116 if self._PackageEnergyJoules() <= 0:
117 logging.info('Cannot monitor power: no energy readings.')
120 if self._TemperatureCelsius() <= 0:
121 logging.info('Cannot monitor power: no temperature readings.')
124 logging.info('Cannot monitor power: %s' % e)
128 def _WinCanMonitorPower(self):
129 family, model = map(int, re.match('.+ Family ([0-9]+) Model ([0-9]+)',
130 platform.processor()).groups())
131 if not _IsSandyBridgeOrLater(platform.processor(), family, model):
132 logging.info('Cannot monitor power: pre-Sandy Bridge CPU.')
135 return self._CheckMSRs()
137 def _LinuxCanMonitorPower(self):
138 if not _LinuxCheckCPU():
140 return self._CheckMSRs()