11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport logging 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport platform 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport re 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifrom telemetry import decorators 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifrom telemetry.core.platform import power_monitor 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMSR_RAPL_POWER_UNIT = 0x606 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMSR_PKG_ENERGY_STATUS = 0x611 # Whole package 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMSR_PP0_ENERGY_STATUS = 0x639 # Core 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMSR_PP1_ENERGY_STATUS = 0x641 # Uncore 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMSR_DRAM_ENERGY_STATUS = 0x619 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciIA32_PACKAGE_THERM_STATUS = 0x1b1 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciIA32_TEMPERATURE_TARGET = 0x1a2 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _JoulesToMilliwattHours(value_joules): 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return value_joules * 1000 / 3600. 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _IsSandyBridgeOrLater(vendor, family, model): 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # Model numbers from: 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # https://software.intel.com/en-us/articles/intel-architecture-and- \ 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # processor-identification-with-cpuid-model-and-family-numbers 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # http://www.speedtraq.com 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return ('Intel' in vendor and family == 6 and 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (model in (0x2A, 0x2D) or model >= 0x30)) 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef _LinuxCheckCPU(): 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci vendor = None 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci family = None 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci model = None 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci cpuinfo = open('/proc/cpuinfo').read().splitlines() 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for line in cpuinfo: 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if vendor and family and model: 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci break 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if line.startswith('vendor_id'): 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci vendor = line.split('\t')[1] 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci elif line.startswith('cpu family'): 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci family = int(line.split(' ')[2]) 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci elif line.startswith('model\t\t'): 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci model = int(line.split(' ')[1]) 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if not _IsSandyBridgeOrLater(vendor, family, model): 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci logging.info('Cannot monitor power: pre-Sandy Bridge CPU.') 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return True 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass MsrPowerMonitor(power_monitor.PowerMonitor): 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def __init__(self, backend): 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci super(MsrPowerMonitor, self).__init__() 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._backend = backend 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._start_energy_j = None 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._start_temp_c = None 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def CanMonitorPower(self): 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if self._backend.GetOSName() == 'win': 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return self._WinCanMonitorPower() 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci elif self._backend.GetOSName() == 'linux': 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return self._LinuxCanMonitorPower() 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def StartMonitoringPower(self, browser): 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert self._start_energy_j is None and self._start_temp_c is None, ( 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'Called StartMonitoringPower() twice.') 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._start_energy_j = self._PackageEnergyJoules() 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._start_temp_c = self._TemperatureCelsius() 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def StopMonitoringPower(self): 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci assert not(self._start_energy_j is None or self._start_temp_c is None), ( 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'Called StopMonitoringPower() before StartMonitoringPower().') 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci energy_consumption_j = self._PackageEnergyJoules() - self._start_energy_j 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci average_temp_c = (self._TemperatureCelsius() + self._start_temp_c) / 2. 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if energy_consumption_j < 0: # Correct overflow. 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # The energy portion of the MSR is 4 bytes. 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci energy_consumption_j += 2 ** 32 * self._EnergyMultiplier() 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._start_energy_j = None 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._start_temp_c = None 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return { 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'identifier': 'msr', 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'energy_consumption_mwh': _JoulesToMilliwattHours(energy_consumption_j), 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'component_utilization': { 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'whole_package': { 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'average_temperature_c': average_temp_c, 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }, 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }, 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci @decorators.Cache 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _EnergyMultiplier(self): 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return 0.5 ** self._backend.ReadMsr(MSR_RAPL_POWER_UNIT, 8, 5) 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _PackageEnergyJoules(self): 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return (self._backend.ReadMsr(MSR_PKG_ENERGY_STATUS, 0, 32) * 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._EnergyMultiplier()) 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _TemperatureCelsius(self): 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tcc_activation_temp = self._backend.ReadMsr(IA32_TEMPERATURE_TARGET, 16, 7) 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if tcc_activation_temp <= 0: 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tcc_activation_temp = 105 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci package_temp_headroom = self._backend.ReadMsr( 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci IA32_PACKAGE_THERM_STATUS, 16, 7) 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return tcc_activation_temp - package_temp_headroom 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _CheckMSRs(self): 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci try: 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if self._PackageEnergyJoules() <= 0: 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci logging.info('Cannot monitor power: no energy readings.') 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if self._TemperatureCelsius() <= 0: 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci logging.info('Cannot monitor power: no temperature readings.') 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci except OSError as e: 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci logging.info('Cannot monitor power: %s' % e) 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return True 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _WinCanMonitorPower(self): 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci family, model = map(int, re.match('.+ Family ([0-9]+) Model ([0-9]+)', 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci platform.processor()).groups()) 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if not _IsSandyBridgeOrLater(platform.processor(), family, model): 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci logging.info('Cannot monitor power: pre-Sandy Bridge CPU.') 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return self._CheckMSRs() 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def _LinuxCanMonitorPower(self): 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if not _LinuxCheckCPU(): 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return False 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return self._CheckMSRs() 141