| Index: tools/telemetry/telemetry/core/platform/power_monitor/msr_power_monitor.py
|
| diff --git a/tools/telemetry/telemetry/core/platform/power_monitor/msr_power_monitor.py b/tools/telemetry/telemetry/core/platform/power_monitor/msr_power_monitor.py
|
| index 038346dfebad4fa71614f4f346a388ca514833f9..80b9f5f26838a4f67e879d172f7c0f0a2fbb27c1 100644
|
| --- a/tools/telemetry/telemetry/core/platform/power_monitor/msr_power_monitor.py
|
| +++ b/tools/telemetry/telemetry/core/platform/power_monitor/msr_power_monitor.py
|
| @@ -2,12 +2,19 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| +import atexit
|
| +import ctypes
|
| import logging
|
| +import os
|
| import platform
|
| import re
|
| +import sys
|
| +import zipfile
|
|
|
| from telemetry import decorators
|
| from telemetry.core.platform import power_monitor
|
| +from telemetry.util import cloud_storage
|
| +from telemetry.util import path
|
|
|
|
|
| MSR_RAPL_POWER_UNIT = 0x606
|
| @@ -17,6 +24,100 @@
|
| MSR_DRAM_ENERGY_STATUS = 0x619
|
| IA32_PACKAGE_THERM_STATUS = 0x1b1
|
| IA32_TEMPERATURE_TARGET = 0x1a2
|
| +
|
| +
|
| +WINRING0_STATUS_MESSAGES = (
|
| + 'No error',
|
| + 'Unsupported platform',
|
| + 'Driver not loaded. You may need to run as Administrator',
|
| + 'Driver not found',
|
| + 'Driver unloaded by other process',
|
| + 'Driver not loaded because of executing on Network Drive',
|
| + 'Unknown error',
|
| +)
|
| +
|
| +
|
| +# The DLL initialization is global, so put it in a global variable.
|
| +_winring0 = None
|
| +
|
| +
|
| +class WinRing0Error(OSError):
|
| + pass
|
| +
|
| +
|
| +@decorators.Cache
|
| +def WinRing0Path():
|
| + python_is_64_bit = sys.maxsize > 2 ** 32
|
| + win_binary_dir = os.path.join(path.GetTelemetryDir(), 'bin', 'win')
|
| + dll_file_name = 'WinRing0x64.dll' if python_is_64_bit else 'WinRing0.dll'
|
| + dll_path = os.path.join(win_binary_dir, dll_file_name)
|
| +
|
| + os_is_64_bit = 'PROGRAMFILES(X86)' in os.environ
|
| + executable_dir = os.path.dirname(sys.executable)
|
| + driver_file_name = 'WinRing0x64.sys' if os_is_64_bit else 'WinRing0.sys'
|
| + driver_path = os.path.join(executable_dir, driver_file_name)
|
| +
|
| + # Check for WinRing0 and download if needed.
|
| + if not (os.path.exists(dll_path) and os.path.exists(driver_path)):
|
| + zip_path = os.path.join(win_binary_dir, 'winring0.zip')
|
| + cloud_storage.GetIfChanged(zip_path, bucket=cloud_storage.PUBLIC_BUCKET)
|
| + try:
|
| + with zipfile.ZipFile(zip_path, 'r') as zip_file:
|
| + # Install DLL.
|
| + if not os.path.exists(dll_path):
|
| + zip_file.extract(dll_file_name, win_binary_dir)
|
| + # Install kernel driver.
|
| + if not os.path.exists(driver_path):
|
| + zip_file.extract(driver_file_name, executable_dir)
|
| + finally:
|
| + os.remove(zip_path)
|
| +
|
| + return dll_path
|
| +
|
| +
|
| +def _Initialize():
|
| + global _winring0
|
| + if not _winring0:
|
| + winring0 = ctypes.WinDLL(WinRing0Path())
|
| + if not winring0.InitializeOls():
|
| + winring0_status = winring0.GetDllStatus()
|
| + raise WinRing0Error(winring0_status,
|
| + 'Unable to initialize WinRing0: %s' %
|
| + WINRING0_STATUS_MESSAGES[winring0_status])
|
| + _winring0 = winring0
|
| + atexit.register(_Deinitialize)
|
| +
|
| +
|
| +def _Deinitialize():
|
| + global _winring0
|
| + if _winring0:
|
| + _winring0.DeinitializeOls()
|
| + _winring0 = None
|
| +
|
| +
|
| +def _ReadMsr(msr_number):
|
| + low = ctypes.c_uint()
|
| + high = ctypes.c_uint()
|
| + _winring0.Rdmsr(ctypes.c_uint(msr_number),
|
| + ctypes.byref(low), ctypes.byref(high))
|
| + return high.value << 32 | low.value
|
| +
|
| +
|
| +@decorators.Cache
|
| +def _EnergyMultiplier():
|
| + return 0.5 ** ((_ReadMsr(MSR_RAPL_POWER_UNIT) >> 8) & 0x1f)
|
| +
|
| +
|
| +def _PackageEnergyJoules():
|
| + return _ReadMsr(MSR_PKG_ENERGY_STATUS) * _EnergyMultiplier()
|
| +
|
| +
|
| +def _TemperatureCelsius():
|
| + tcc_activation_temp = _ReadMsr(IA32_TEMPERATURE_TARGET) >> 16 & 0x7f
|
| + if tcc_activation_temp <= 0:
|
| + tcc_activation_temp = 105
|
| + package_temp_headroom = _ReadMsr(IA32_PACKAGE_THERM_STATUS) >> 16 & 0x7f
|
| + return tcc_activation_temp - package_temp_headroom
|
|
|
|
|
| def _JoulesToMilliwattHours(value_joules):
|
| @@ -48,15 +149,16 @@
|
| return False
|
|
|
| try:
|
| - if self._PackageEnergyJoules() <= 0:
|
| - logging.info('Cannot monitor power: no energy readings.')
|
| - return False
|
| + _Initialize()
|
| + except OSError:
|
| + return False
|
|
|
| - if self._TemperatureCelsius() <= 0:
|
| - logging.info('Cannot monitor power: no temperature readings.')
|
| - return False
|
| - except OSError as e:
|
| - logging.info('Cannot monitor power: %s' % e)
|
| + if _PackageEnergyJoules() <= 0:
|
| + logging.info('Cannot monitor power: no energy readings.')
|
| + return False
|
| +
|
| + if _TemperatureCelsius() <= 0:
|
| + logging.info('Cannot monitor power: no temperature readings.')
|
| return False
|
|
|
| return True
|
| @@ -64,15 +166,16 @@
|
| def StartMonitoringPower(self, browser):
|
| assert self._start_energy_j is None and self._start_temp_c is None, (
|
| 'Called StartMonitoringPower() twice.')
|
| - self._start_energy_j = self._PackageEnergyJoules()
|
| - self._start_temp_c = self._TemperatureCelsius()
|
| + _Initialize()
|
| + self._start_energy_j = _PackageEnergyJoules()
|
| + self._start_temp_c = _TemperatureCelsius()
|
|
|
| def StopMonitoringPower(self):
|
| assert not(self._start_energy_j is None or self._start_temp_c is None), (
|
| 'Called StopMonitoringPower() before StartMonitoringPower().')
|
|
|
| - energy_consumption_j = self._PackageEnergyJoules() - self._start_energy_j
|
| - average_temp_c = (self._TemperatureCelsius() + self._start_temp_c) / 2.
|
| + energy_consumption_j = _PackageEnergyJoules() - self._start_energy_j
|
| + average_temp_c = (_TemperatureCelsius() + self._start_temp_c) / 2.
|
| assert energy_consumption_j >= 0, ('Negative energy consumption. (Starting '
|
| 'energy was %s.)' % self._start_energy_j)
|
|
|
| @@ -88,20 +191,3 @@
|
| },
|
| },
|
| }
|
| -
|
| - @decorators.Cache
|
| - def _EnergyMultiplier(self):
|
| - return 0.5 ** ((self._backend.ReadMsr(MSR_RAPL_POWER_UNIT) >> 8) & 0x1f)
|
| -
|
| - def _PackageEnergyJoules(self):
|
| - return (self._backend.ReadMsr(MSR_PKG_ENERGY_STATUS) *
|
| - self._EnergyMultiplier())
|
| -
|
| - def _TemperatureCelsius(self):
|
| - tcc_activation_temp = (
|
| - self._backend.ReadMsr(IA32_TEMPERATURE_TARGET) >> 16 & 0x7f)
|
| - if tcc_activation_temp <= 0:
|
| - tcc_activation_temp = 105
|
| - package_temp_headroom = (
|
| - self._backend.ReadMsr(IA32_PACKAGE_THERM_STATUS) >> 16 & 0x7f)
|
| - return tcc_activation_temp - package_temp_headroom
|
|
|