Index: tools/telemetry/telemetry/core/platform/power_monitor/ippet_power_monitor.py |
diff --git a/tools/telemetry/telemetry/core/platform/power_monitor/ippet_power_monitor.py b/tools/telemetry/telemetry/core/platform/power_monitor/ippet_power_monitor.py |
deleted file mode 100644 |
index c4619e1b8dc69713707b664e6326f91d8b9b0dc5..0000000000000000000000000000000000000000 |
--- a/tools/telemetry/telemetry/core/platform/power_monitor/ippet_power_monitor.py |
+++ /dev/null |
@@ -1,258 +0,0 @@ |
-# Copyright 2014 The Chromium Authors. All rights reserved. |
-# Use of this source code is governed by a BSD-style license that can be |
-# found in the LICENSE file. |
- |
-import contextlib |
-import csv |
-import logging |
-import operator |
-import os |
-import platform |
-import re |
-import shutil |
-import tempfile |
-import zipfile |
- |
-from telemetry.core.platform import platform_backend |
-from telemetry.core.platform import power_monitor |
-from telemetry import decorators |
-from telemetry.util import cloud_storage |
-from telemetry.util import path |
-from telemetry.util import statistics |
- |
-try: |
- import win32con # pylint: disable=F0401 |
- import win32event # pylint: disable=F0401 |
- import win32process # pylint: disable=F0401 |
-except ImportError: |
- win32con = None |
- win32event = None |
- win32process = None |
- |
- |
-START_EVENT = 'ippet_StartEvent' |
-QUIT_EVENT = 'ippet_QuitEvent' |
- |
- |
-class IppetError(Exception): |
- pass |
- |
- |
-@decorators.Cache |
-def IppetPath(): |
- # Look for pre-installed IPPET. |
- ippet_path = path.FindInstalledWindowsApplication(os.path.join( |
- 'Intel', 'Intel(R) Platform Power Estimation Tool', 'ippet.exe')) |
- if ippet_path: |
- return ippet_path |
- |
- # Look for IPPET installed previously by this script. |
- ippet_path = os.path.join( |
- path.GetTelemetryDir(), 'bin', 'win', 'ippet', 'ippet.exe') |
- if path.IsExecutable(ippet_path): |
- return ippet_path |
- |
- # Install IPPET. |
- zip_path = os.path.join(path.GetTelemetryDir(), 'bin', 'win', 'ippet.zip') |
- cloud_storage.GetIfChanged(zip_path, bucket=cloud_storage.PUBLIC_BUCKET) |
- with zipfile.ZipFile(zip_path, 'r') as zip_file: |
- zip_file.extractall(os.path.dirname(zip_path)) |
- os.remove(zip_path) |
- |
- if path.IsExecutable(ippet_path): |
- return ippet_path |
- |
- return None |
- |
- |
-class IppetPowerMonitor(power_monitor.PowerMonitor): |
- def __init__(self, backend): |
- super(IppetPowerMonitor, self).__init__() |
- self._backend = backend |
- self._ippet_handle = None |
- self._output_dir = None |
- |
- def CanMonitorPower(self): |
- if not win32event: |
- return False |
- |
- # TODO(dtu): This should work on Windows 7, but it's flaky on the bots. |
- # http://crbug.com/336558 |
- windows_8_or_later = ( |
- self._backend.GetOSName() == 'win' and |
- self._backend.GetOSVersionName() >= platform_backend.WIN8) |
- if not windows_8_or_later: |
- return False |
- |
- # This check works on Windows only. |
- family, model = map(int, re.match('.+ Family ([0-9]+) Model ([0-9]+)', |
- platform.processor()).groups()) |
- # Model numbers from: |
- # https://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers |
- # http://www.speedtraq.com |
- sandy_bridge_or_later = ('Intel' in platform.processor() and family == 6 and |
- (model in (0x2A, 0x2D) or model >= 0x30)) |
- if not sandy_bridge_or_later: |
- return False |
- |
- if not IppetPath(): |
- return False |
- |
- return True |
- |
- def CanMeasurePerApplicationPower(self): |
- return self.CanMonitorPower() |
- |
- def StartMonitoringPower(self, browser): |
- assert not self._ippet_handle, 'Called StartMonitoringPower() twice.' |
- self._output_dir = tempfile.mkdtemp() |
- parameters = ['-log_dir', self._output_dir, '-signals', 'START,QUIT', |
- '-battery', 'n', '-disk', 'n', '-gpu', 'n', |
- '-enable_web', 'n', '-zip', 'n', '-i', '0.1'] |
- |
- try: |
- with contextlib.closing(win32event.CreateEvent( |
- None, True, False, START_EVENT)) as start_event: |
- self._ippet_handle = self._backend.LaunchApplication( |
- IppetPath(), parameters, elevate_privilege=True) |
- wait_code = win32event.WaitForSingleObject(start_event, 5000) |
- if wait_code != win32event.WAIT_OBJECT_0: |
- if wait_code == win32event.WAIT_TIMEOUT: |
- raise IppetError('Timed out waiting for IPPET to start.') |
- else: |
- raise IppetError('Error code %d while waiting for IPPET to start.' % |
- wait_code) |
- |
- except: # In case of emergency, don't leave IPPET processes hanging around. |
- if self._ippet_handle: |
- try: |
- exit_code = win32process.GetExitCodeProcess(self._ippet_handle) |
- if exit_code == win32con.STILL_ACTIVE: |
- win32process.TerminateProcess(self._ippet_handle, 0) |
- finally: |
- self._ippet_handle.Close() |
- self._ippet_handle = None |
- raise |
- |
- def StopMonitoringPower(self): |
- assert self._ippet_handle, ( |
- 'Called StopMonitoringPower() before StartMonitoringPower().') |
- try: |
- # Stop IPPET. |
- with contextlib.closing(win32event.OpenEvent( |
- win32event.EVENT_MODIFY_STATE, False, QUIT_EVENT)) as quit_event: |
- win32event.SetEvent(quit_event) |
- |
- # Wait for IPPET process to exit. |
- wait_code = win32event.WaitForSingleObject(self._ippet_handle, 20000) |
- if wait_code != win32event.WAIT_OBJECT_0: |
- if wait_code == win32event.WAIT_TIMEOUT: |
- raise IppetError('Timed out waiting for IPPET to close.') |
- else: |
- raise IppetError('Error code %d while waiting for IPPET to close.' % |
- wait_code) |
- |
- finally: # If we need to, forcefully kill IPPET. |
- try: |
- exit_code = win32process.GetExitCodeProcess(self._ippet_handle) |
- if exit_code == win32con.STILL_ACTIVE: |
- win32process.TerminateProcess(self._ippet_handle, 0) |
- raise IppetError('IPPET is still running but should have stopped.') |
- elif exit_code != 0: |
- raise IppetError('IPPET closed with exit code %d.' % exit_code) |
- finally: |
- self._ippet_handle.Close() |
- self._ippet_handle = None |
- |
- # Read IPPET's log file. |
- log_file = os.path.join(self._output_dir, 'ippet_log_processes.xls') |
- try: |
- with open(log_file, 'r') as f: |
- reader = csv.DictReader(f, dialect='excel-tab') |
- data = list(reader)[1:] # The first iteration only reports temperature. |
- except IOError: |
- logging.error('Output directory %s contains: %s', |
- self._output_dir, os.listdir(self._output_dir)) |
- raise |
- shutil.rmtree(self._output_dir) |
- self._output_dir = None |
- |
- def get(*args, **kwargs): |
- """Pull all iterations of a field from the IPPET data as a list. |
- |
- Args: |
- args: A list representing the field name. |
- mult: A cosntant to multiply the field's value by, for unit conversions. |
- default: The default value if the field is not found in the iteration. |
- |
- Returns: |
- A list containing the field's value across all iterations. |
- """ |
- key = '\\\\.\\' + '\\'.join(args) |
- def value(line): |
- if key in line: |
- return line[key] |
- elif 'default' in kwargs: |
- return kwargs['default'] |
- else: |
- raise KeyError('Key "%s" not found in data and ' |
- 'no default was given.' % key) |
- return [float(value(line)) * kwargs.get('mult', 1) for line in data] |
- |
- result = { |
- 'identifier': 'ippet', |
- 'power_samples_mw': get('Power(_Total)', 'Package W', mult=1000), |
- 'energy_consumption_mwh': |
- sum(map(operator.mul, |
- get('Power(_Total)', 'Package W', mult=1000), |
- get('sys', 'Interval(secs)', mult=1./3600.))), |
- 'component_utilization': { |
- 'whole_package': { |
- 'average_temperature_c': |
- statistics.ArithmeticMean(get( |
- 'Temperature(Package)', 'Current C')), |
- }, |
- 'cpu': { |
- 'power_samples_mw': get('Power(_Total)', 'CPU W', mult=1000), |
- 'energy_consumption_mwh': |
- sum(map(operator.mul, |
- get('Power(_Total)', 'CPU W', mult=1000), |
- get('sys', 'Interval(secs)', mult=1./3600.))), |
- }, |
- 'disk': { |
- 'power_samples_mw': get('Power(_Total)', 'Disk W', mult=1000), |
- 'energy_consumption_mwh': |
- sum(map(operator.mul, |
- get('Power(_Total)', 'Disk W', mult=1000), |
- get('sys', 'Interval(secs)', mult=1./3600.))), |
- }, |
- 'gpu': { |
- 'power_samples_mw': get('Power(_Total)', 'GPU W', mult=1000), |
- 'energy_consumption_mwh': |
- sum(map(operator.mul, |
- get('Power(_Total)', 'GPU W', mult=1000), |
- get('sys', 'Interval(secs)', mult=1./3600.))), |
- }, |
- }, |
- } |
- |
- # Find Chrome processes in data. Note that this won't work if there are |
- # extra Chrome processes lying around. |
- chrome_keys = set() |
- for iteration in data: |
- for key in iteration.iterkeys(): |
- parts = key.split('\\') |
- if (len(parts) >= 4 and |
- re.match(r'Process\(Google Chrome [0-9]+\)', parts[3])): |
- chrome_keys.add(parts[3]) |
- # Add Chrome process power usage to result. |
- # Note that this is only an estimate of Chrome's CPU power usage. |
- if chrome_keys: |
- per_process_power_usage = [ |
- get(key, 'CPU Power W', default=0, mult=1000) for key in chrome_keys] |
- result['application_energy_consumption_mwh'] = ( |
- sum(map(operator.mul, |
- map(sum, zip(*per_process_power_usage)), |
- get('sys', 'Interval(secs)', mult=1./3600.)))) |
- |
- return result |