Commit dcf3f642 authored by tmandel@chromium.org's avatar tmandel@chromium.org

Added frequency stats and c-state residency to CrOS power monitor.

BUG=336561

Review URL: https://codereview.chromium.org/352583007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284183 0039d316-1c4b-4281-b951-d872f2087c98
parent bddf240a
......@@ -77,4 +77,4 @@ class CrosPlatformBackend(
self._powermonitor.StartMonitoringPower(browser)
def StopMonitoringPower(self):
self._powermonitor.StopMonitoringPower()
return self._powermonitor.StopMonitoringPower()
......@@ -6,10 +6,12 @@ import collections
import re
from telemetry import decorators
from telemetry.core.platform import power_monitor
from telemetry.core.platform.power_monitor import cros_sysfs_platform
from telemetry.core.platform.power_monitor import sysfs_power_monitor
CPU_PATH = '/sys/devices/system/cpu/'
class CrosPowerMonitor(power_monitor.PowerMonitor):
class CrosPowerMonitor(sysfs_power_monitor.SysfsPowerMonitor):
"""PowerMonitor that relies on 'power_supply_info' to monitor power
consumption of a single ChromeOS application.
"""
......@@ -22,39 +24,30 @@ class CrosPowerMonitor(power_monitor.PowerMonitor):
Attributes:
_browser: The browser to monitor.
_cri: The Chrome interface.
_final_stats: The result of 'power_supply_info' after the test.
_initial_stats: The result of 'power_supply_info' before the test.
_start_time: The time the test started monitoring power.
_initial_power: The result of 'power_supply_info' before the test.
"""
super(CrosPowerMonitor, self).__init__()
super(CrosPowerMonitor, self).__init__(
cros_sysfs_platform.CrosSysfsPlatform(cri))
self._browser = None
self._cri = cri
self._final_stats = None
self._initial_stats = None
self._start_time = None
self._initial_power = None
@decorators.Cache
def CanMonitorPower(self):
return self._IsOnBatteryPower()
def StartMonitoringPower(self, browser):
assert not self._browser, 'Must call StopMonitoringPower().'
self._browser = browser
# The time on the device is recorded to determine the length of the test.
self._start_time = self._browser.cpu_stats['Gpu']['TotalTime']
self._initial_stats = self._cri.RunCmdOnDevice(['power_supply_info'])[0]
super(CrosPowerMonitor, self).StartMonitoringPower(browser)
self._initial_power = self._cri.RunCmdOnDevice(['power_supply_info'])[0]
def StopMonitoringPower(self):
assert self._browser, 'StartMonitoringPower() not called.'
try:
# The length of the test is used to measure energy consumption.
length_h = (self._browser.cpu_stats['Gpu']['TotalTime'] -
self._start_time) / (3600 * 10 ** 3)
self._final_stats = self._cri.RunCmdOnDevice(['power_supply_info'])[0]
return CrosPowerMonitor.ParseSamplingOutput(self._initial_stats,
self._final_stats, length_h)
finally:
self._browser = None
cpu_stats = super(CrosPowerMonitor, self).StopMonitoringPower()
final_power = self._cri.RunCmdOnDevice(['power_supply_info'])[0]
# The length of the test is used to measure energy consumption.
length_h = (self._end_time - self._start_time) / 3600.0
power_stats = CrosPowerMonitor.ParsePower(
self._initial_power, final_power, length_h)
return CrosPowerMonitor.CombineResults(cpu_stats, power_stats)
@staticmethod
def IsOnBatteryPower(status, board):
......@@ -69,7 +62,7 @@ class CrosPowerMonitor(power_monitor.PowerMonitor):
"""
on_battery = status['Line Power']['online'] == 'no'
# Butterfly can incorrectly report AC online for some time after unplug.
# Check batter discharge state to confirm.
# Check battery discharge state to confirm.
if board == 'butterfly':
on_battery |= status['Battery']['state'] == 'Discharging'
return on_battery
......@@ -110,10 +103,10 @@ class CrosPowerMonitor(power_monitor.PowerMonitor):
rv[dev][kname[0]] = result[0][1]
else:
rv[dev][result[0][0]] = result[0][1]
return rv
return dict(rv)
@staticmethod
def ParseSamplingOutput(initial_stats, final_stats, length_h):
def ParsePower(initial_stats, final_stats, length_h):
"""Parse output of 'power_supply_info'
Args:
......@@ -124,25 +117,47 @@ class CrosPowerMonitor(power_monitor.PowerMonitor):
Returns:
Dictionary in the format returned by StopMonitoringPower().
"""
out_dict = {'identifier': 'power_supply_info', 'power_samples_mw': []}
out_dict = {'identifier': 'power_supply_info'}
component_utilization = {}
initial = CrosPowerMonitor.ParsePowerSupplyInfo(initial_stats)
final = CrosPowerMonitor.ParsePowerSupplyInfo(final_stats)
# The charge value reported by 'power_supply_info' is not precise enough to
# give meaningful results across shorter tests, so average energy rate and
# the length of the test are used.
average_power_mw = (float(initial['Battery']['energy rate']) +
float(final['Battery']['energy rate'])) * 10 ** 3 / 2.0
out_dict['power_samples_mw'].append(average_power_mw)
initial_power_mw = float(initial['Battery']['energy rate']) * 10 ** 3
final_power_mw = float(final['Battery']['energy rate']) * 10 ** 3
average_power_mw = (initial_power_mw + final_power_mw) / 2.0
out_dict['power_samples_mw'] = [initial_power_mw, final_power_mw]
out_dict['energy_consumption_mwh'] = average_power_mw * length_h
# Duplicating CrOS battery fields where applicable.
whole_package = {}
whole_package['charge_full'] = float(final['Battery']['full charge'])
whole_package['charge_full_design'] = (
battery = {}
battery['charge_full'] = float(final['Battery']['full charge'])
battery['charge_full_design'] = (
float(final['Battery']['full charge design']))
whole_package['charge_now'] = float(final['Battery']['charge'])
whole_package['current_now'] = float(final['Battery']['current'])
whole_package['energy'] = float(final['Battery']['energy'])
whole_package['energy_rate'] = float(final['Battery']['energy rate'])
whole_package['voltage_now'] = float(final['Battery']['voltage'])
out_dict['component_utilization'] = {'whole_package': whole_package}
battery['charge_now'] = float(final['Battery']['charge'])
battery['current_now'] = float(final['Battery']['current'])
battery['energy'] = float(final['Battery']['energy'])
battery['energy_rate'] = float(final['Battery']['energy rate'])
battery['voltage_now'] = float(final['Battery']['voltage'])
component_utilization['battery'] = battery
out_dict['component_utilization'] = component_utilization
return out_dict
@staticmethod
def CombineResults(cpu_stats, power_stats):
"""Add frequency and c-state residency data to the power data.
Args:
cpu_stats: Dictionary of CPU data gathered from SysfsPowerMonitor.
power_stats: Dictionary containing power statistics.
Returns:
Dictionary in the format returned by StopMonitoringPower.
"""
if not cpu_stats:
return power_stats
comp_util = power_stats['component_utilization']
# Add CPU stats to power stat dictionary.
for cpu in cpu_stats:
comp_util[cpu] = cpu_stats[cpu]
return power_stats
......@@ -8,7 +8,7 @@ from telemetry.core.platform.power_monitor import cros_power_monitor
class CrosPowerMonitorMonitorTest(unittest.TestCase):
initial = ('''Device: Line Power
initial_power = ('''Device: Line Power
path: /sys/class/power_supply/AC
online: no
type: Mains
......@@ -32,7 +32,7 @@ Device: Battery
percentage: 70.1985
display percentage: 73.9874
technology: Li-ion''')
final = ('''Device: Line Power
final_power = ('''Device: Line Power
path: /sys/class/power_supply/AC
online: yes
type: Mains
......@@ -56,25 +56,186 @@ Device: Battery
percentage: 70.1985
display percentage: 73.9874
technology: Li-ion''')
def testEnergyConsumption(self):
results = cros_power_monitor.CrosPowerMonitor.ParseSamplingOutput(
self.initial, self.final, .2)
self.assertAlmostEqual(results['energy_consumption_mwh'], 2558.42)
self.assertAlmostEqual(results['power_samples_mw'][0], 12792.1)
whole_package = results['component_utilization']['whole_package']
self.assertEqual(whole_package['charge_full'], 4.03)
self.assertEqual(whole_package['charge_full_design'], 4.03)
self.assertEqual(whole_package['charge_now'], 2.827)
self.assertEqual(whole_package['energy'], 31.8262)
self.assertEqual(whole_package['energy_rate'], 12.7993)
self.assertEqual(whole_package['voltage_now'], 12.238)
expected_parsing_power = {
'Line Power': {
'path': '/sys/class/power_supply/AC',
'online': 'no',
'type': 'Mains',
'enum type': 'Disconnected',
'voltage': '0',
'current': '0'
},
'Battery': {
'path': '/sys/class/power_supply/BAT0',
'vendor': 'SANYO',
'model name': 'AP13J3K',
'serial number': '0061',
'state': 'Discharging',
'voltage': '11.816',
'energy': '31.8262',
'energy rate': '12.7849',
'current': '1.082',
'charge': '2.829',
'full charge': '4.03',
'full charge design': '4.03',
'percentage': '70.1985',
'display percentage': '73.9874',
'technology': 'Li-ion'
}
}
expected_power = {
'energy_consumption_mwh': 2558.42,
'power_samples_mw': [12784.9, 12799.3],
'component_utilization': {
'battery': {
'charge_full': 4.03,
'charge_full_design': 4.03,
'charge_now': 2.827,
'current_now': 1.082,
'energy': 31.8262,
'energy_rate': 12.7993,
'voltage_now': 12.238
}
}
}
expected_cpu = {
'whole_package': {
'frequency_percent': {
1700000000: 3.29254111574526,
1600000000: 0.0,
1500000000: 0.0,
1400000000: 0.15926805099535601,
1300000000: 0.47124116307273645,
1200000000: 0.818756100807525,
1100000000: 1.099381692400982,
1000000000: 2.5942528544384302,
900000000: 5.68661122326737,
800000000: 3.850545467654628,
700000000: 2.409691872245393,
600000000: 1.4693702487650486,
500000000: 2.4623575553879373,
400000000: 2.672038150383057,
300000000: 3.415770495015825,
200000000: 69.59817400982045
},
'cstate_residency_percent': {
'C0': 83.67623835616438535,
'C1': 0.2698609589041096,
'C2': 0.2780191780821918,
'C3': 15.77588150684931505
}
},
'cpu0': {
'frequency_percent': {
1700000000: 4.113700564971752,
1600000000: 0.0,
1500000000: 0.0,
1400000000: 0.1765536723163842,
1300000000: 0.4943502824858757,
1200000000: 0.7944915254237288,
1100000000: 1.2226341807909604,
1000000000: 3.0632062146892656,
900000000: 5.680614406779661,
800000000: 3.6679025423728815,
700000000: 2.379060734463277,
600000000: 1.4124293785310735,
500000000: 2.599752824858757,
400000000: 3.0102401129943503,
300000000: 3.650247175141243,
200000000: 67.73481638418079
},
'cstate_residency_percent': {
'C0': 76.76226164383562,
'C1': 0.3189164383561644,
'C2': 0.4544301369863014,
'C3': 22.4643917808219178
}
},
'cpu1': {
'frequency_percent': {
1700000000: 2.4713816665187682,
1600000000: 0.0,
1500000000: 0.0,
1400000000: 0.1419824296743278,
1300000000: 0.44813204365959713,
1200000000: 0.8430206761913214,
1100000000: 0.9761292040110037,
1000000000: 2.1252994941875945,
900000000: 5.69260803975508,
800000000: 4.033188392936374,
700000000: 2.4403230100275093,
600000000: 1.526311118999024,
500000000: 2.3249622859171177,
400000000: 2.3338361877717633,
300000000: 3.1812938148904073,
200000000: 71.46153163546012
},
'cstate_residency_percent': {
'C0': 90.5902150684931507,
'C1': 0.2208054794520548,
'C2': 0.1016082191780822,
'C3': 9.0873712328767123
}
}
}
def testParsePowerSupplyInfo(self):
result = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
self.initial_power)
self.assertDictEqual(result, self.expected_parsing_power)
def testParsePower(self):
results = cros_power_monitor.CrosPowerMonitor.ParsePower(
self.initial_power, self.final_power, 0.2)
for value in results['component_utilization']['battery']:
self.assertAlmostEqual(
results['component_utilization']['battery'][value],
self.expected_power['component_utilization']['battery'][value])
self.assertAlmostEqual(results['energy_consumption_mwh'],
self.expected_power['energy_consumption_mwh'])
self.assertAlmostEqual(results['power_samples_mw'][0],
self.expected_power['power_samples_mw'][0])
self.assertAlmostEqual(results['power_samples_mw'][1],
self.expected_power['power_samples_mw'][1])
def testCombineResults(self):
result = cros_power_monitor.CrosPowerMonitor.CombineResults(
self.expected_cpu, self.expected_power)
comp_util = result['component_utilization']
# Test power values.
self.assertEqual(result['energy_consumption_mwh'],
self.expected_power['energy_consumption_mwh'])
self.assertEqual(result['power_samples_mw'],
self.expected_power['power_samples_mw'])
self.assertEqual(comp_util['battery'],
self.expected_power['component_utilization']['battery'])
# Test frequency values.
self.assertDictEqual(
comp_util['whole_package']['frequency_percent'],
self.expected_cpu['whole_package']['frequency_percent'])
self.assertDictEqual(
comp_util['cpu0']['frequency_percent'],
self.expected_cpu['cpu0']['frequency_percent'])
self.assertDictEqual(
comp_util['cpu1']['frequency_percent'],
self.expected_cpu['cpu1']['frequency_percent'])
# Test c-state residency values.
self.assertDictEqual(
comp_util['whole_package']['cstate_residency_percent'],
self.expected_cpu['whole_package']['cstate_residency_percent'])
self.assertDictEqual(
comp_util['cpu0']['cstate_residency_percent'],
self.expected_cpu['cpu0']['cstate_residency_percent'])
self.assertDictEqual(
comp_util['cpu1']['cstate_residency_percent'],
self.expected_cpu['cpu1']['cstate_residency_percent'])
def testCanMonitorPower(self):
status = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
self.initial)
self.assertTrue(
cros_power_monitor.CrosPowerMonitor.IsOnBatteryPower(status, 'peppy'))
status = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
self.final)
# TODO(tmandel): Add a test here where the device cannot monitor power.
initial_status = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
self.initial_power)
final_status = cros_power_monitor.CrosPowerMonitor.ParsePowerSupplyInfo(
self.final_power)
self.assertTrue(cros_power_monitor.CrosPowerMonitor.IsOnBatteryPower(
initial_status, 'peppy'))
self.assertTrue(cros_power_monitor.CrosPowerMonitor.IsOnBatteryPower(
status, 'butterfly'))
final_status, 'butterfly'))
# 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.
from telemetry.core.platform.power_monitor import sysfs_platform
class CrosSysfsPlatform(sysfs_platform.SysfsPlatform):
"""A SysfsPlatform implementation to be used for ChromeOS devices."""
def __init__(self, cri):
"""Constructor.
Args:
cri: Chrome interface.
"""
super(CrosSysfsPlatform, self).__init__()
self._cri = cri
def RunShellCommand(self, command):
return self._cri.RunCmdOnDevice(command.split())[0]
@staticmethod
def ParseStateSample(sample, time):
sample_stats = {}
for cpu in sample:
cstates = {'C0': time * 10 ** 6}
values = sample[cpu].splitlines()
num_states = len(values) / 3
names = values[:num_states]
times = values[num_states:2 * num_states]
latencies = values[2 * num_states:]
for i, state in enumerate(names):
if names[i] == 'POLL' and not int(latencies[i]):
# C0 state. Kernel stats aren't right, so calculate by
# subtracting all other states from total time (using epoch
# timer since we calculate differences in the end anyway).
# NOTE: Only x86 lists C0 under cpuidle, ARM does not.
continue
cstates['C0'] -= int(times[i])
if names[i] == '<null>':
# Kernel race condition that can happen while a new C-state gets
# added (e.g. AC->battery). Don't know the 'name' of the state
# yet, but its 'time' would be 0 anyway.
continue
cstates[state] = int(times[i])
sample_stats[cpu] = cstates
return sample_stats
# 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 unittest
from telemetry.core.platform.power_monitor import cros_sysfs_platform
class CrosSysfsPlatformTest(unittest.TestCase):
start_time = 1403211341
initial_cstate = {
'cpu0': 'POLL\nC1\nC2\nC3\n0\n138356189\n102416540\n'
'17158209182\n0\n1\n500\n1000',
'cpu1': 'POLL\nC1\nC2\nC3\n0\n107318149\n81786238\n'
'17348563431\n0\n1\n500\n1000'
}
expected_cstate = {
'cpu0': {
'C0': 1403193942018089,
'C1': 138356189,
'C2': 102416540,
'C3': 17158209182
},
'cpu1': {
'C0': 1403193803332182,
'C1': 107318149,
'C2': 81786238,
'C3': 17348563431
}
}
def testCrosParseCpuStates(self):
# Use mock start and end times to allow for the test to calculate C0.
results = cros_sysfs_platform.CrosSysfsPlatform.ParseStateSample(
self.initial_cstate, self.start_time)
for cpu in results:
for state in results[cpu]:
self.assertAlmostEqual(results[cpu][state],
self.expected_cstate[cpu][state])
# 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.
class SysfsPlatform(object):
"""A platform-specific utility class for running shell commands and properly
gathering c-state data.
"""
def RunShellCommand(self, command):
"""Run command on this particular shell.
Args:
A command string to be executed in the shell.
Returns:
A string containing the results of the command.
"""
raise NotImplementedError()
@staticmethod
def ParseStateSample(sample, time):
"""Parse a single c-state residency sample.
Args:
sample: A sample of c-state residency times to be parsed. Organized as
a dictionary mapping CPU name to a string containing all c-state
names, the times in each state, and the latency of each state all
separated by newlines.
time: The epoch time at which the sample was taken.
Returns:
Dictionary associating a c-state with a time.
"""
raise NotImplementedError()
# 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 collections
import os
import re
from telemetry import decorators
from telemetry.core.platform import power_monitor
CPU_PATH = '/sys/devices/system/cpu/'
class SysfsPowerMonitor(power_monitor.PowerMonitor):
"""PowerMonitor that relies on sysfs to monitor CPU statistics on several
different platforms.
"""
def __init__(self, platform):
"""Constructor.
Args:
platform: A SysfsPlatform object.
Attributes:
_browser: The browser to monitor.
_cpus: A list of the CPUs on the target device.
_end_time: The time the test stopped monitoring power.
_final_cstate: The c-state residency times after the test.
_final_freq: The CPU frequency times after the test.
_initial_cstate: The c-state residency times before the test.
_initial_freq: The CPU frequency times before the test.
_platform: A SysfsPlatform object associated with the target platform.
_start_time: The time the test started monitoring power.
"""
super(SysfsPowerMonitor, self).__init__()
self._browser = None
self._cpus = filter(lambda x: re.match(r'^cpu[0-9]+', x),
platform.RunShellCommand('ls %s' % CPU_PATH).split())
self._end_time = None
self._final_cstate = None
self._final_freq = None
self._initial_cstate = None
self._initial_freq = None
self._platform = platform
self._start_time = None
@decorators.Cache
def CanMonitorPower(self):
return bool(self._platform.RunShellCommand(
'if [ -e %s ]; then echo true; fi' % CPU_PATH))
def StartMonitoringPower(self, browser):
assert not self._browser, 'Must call StopMonitoringPower().'
self._browser = browser
self._start_time = int(self._platform.RunShellCommand('date +%s'))
if self.CanMonitorPower():
self._initial_freq = self.GetCpuFreq()
self._initial_cstate = self.GetCpuState()
def StopMonitoringPower(self):
assert self._browser, 'StartMonitoringPower() not called.'
try:
self._end_time = int(self._platform.RunShellCommand('date +%s'))
out = {}
if self.CanMonitorPower():
self._final_freq = self.GetCpuFreq()
self._final_cstate = self.GetCpuState()
frequencies = SysfsPowerMonitor.ComputeCpuStats(
SysfsPowerMonitor.ParseFreqSample(self._initial_freq),
SysfsPowerMonitor.ParseFreqSample(self._final_freq))
start_cstate = self._platform.ParseStateSample(
self._initial_cstate, self._start_time)
end_cstate = self._platform.ParseStateSample(
self._final_cstate, self._end_time)
cstates = SysfsPowerMonitor.ComputeCpuStats(start_cstate, end_cstate)
for cpu in frequencies:
out[cpu] = {'frequency_percent': frequencies[cpu]}
out[cpu]['cstate_residency_percent'] = cstates[cpu]
return out
finally:
self._browser = None
def GetCpuState(self):
"""Retrieve CPU c-state residency times from the device.
Returns:
Dictionary containing c-state residency times for each CPU.
"""
stats = {}
for cpu in self._cpus:
cpu_state_path = os.path.join(CPU_PATH, cpu, 'cpuidle/state*')
stats[cpu] = self._platform.RunShellCommand(
'cat %s %s %s' % (os.path.join(cpu_state_path, 'name'),
os.path.join(cpu_state_path, 'time'),
os.path.join(cpu_state_path, 'latency')))
return stats
def GetCpuFreq(self):
"""Retrieve CPU frequency times from the device.
Returns:
Dictionary containing frequency times for each CPU.
"""
stats = {}
for cpu in self._cpus:
cpu_freq_path = os.path.join(
CPU_PATH, cpu, 'cpufreq/stats/time_in_state')
stats[cpu] = self._platform.RunShellCommand('cat %s' % cpu_freq_path)
return stats
@staticmethod
def ParseFreqSample(sample):
"""Parse a single frequency sample.
Args:
sample: The single sample of frequency data to be parsed.
Returns:
A dictionary associating a frequency with a time.
"""
sample_stats = {}
for cpu in sample:
frequencies = {}
for line in sample[cpu].splitlines():
pair = line.split()
freq = int(pair[0]) * 10 ** 3
timeunits = int(pair[1])
if freq in frequencies:
frequencies[freq] += timeunits
else:
frequencies[freq] = timeunits
sample_stats[cpu] = frequencies
return sample_stats
@staticmethod
def ComputeCpuStats(initial, final):
"""Parse the CPU c-state and frequency values saved during monitoring.
Args:
initial: The parsed dictionary of initial statistics to be converted
into percentages.
final: The parsed dictionary of final statistics to be converted
into percentages.
Returns:
Dictionary containing percentages for each CPU as well as an average
across all CPUs.
"""
cpu_stats = {}
# Each core might have different states or frequencies, so keep track of
# the total time in a state or frequency and how many cores report a time.
cumulative_times = collections.defaultdict(lambda: (0, 0))
for cpu in initial:
current_cpu = {}
total = 0
for state in initial[cpu]:
current_cpu[state] = final[cpu][state] - initial[cpu][state]
total += current_cpu[state]
for state in current_cpu:
current_cpu[state] /= (float(total) / 100.0)
# Calculate the average c-state residency across all CPUs.
time, count = cumulative_times[state]
cumulative_times[state] = (time + current_cpu[state], count + 1)
cpu_stats[cpu] = current_cpu
average = {}
for state in cumulative_times:
time, count = cumulative_times[state]
average[state] = time / float(count)
cpu_stats['whole_package'] = average
return cpu_stats
# 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 unittest
from telemetry.core.platform.power_monitor import sysfs_power_monitor
class SysfsPowerMonitorMonitorTest(unittest.TestCase):
initial_freq = {
'cpu0': '1700000 6227\n1600000 0\n1500000 0\n1400000 28\n1300000 22\n'
'1200000 14\n1100000 19\n1000000 22\n900000 14\n800000 20\n'
'700000 15\n600000 23\n500000 23\n400000 9\n300000 28\n200000 179',
'cpu1': '1700000 11491\n1600000 0\n1500000 0\n1400000 248\n1300000 1166\n'
'1200000 2082\n1100000 2943\n1000000 6560\n900000 12517\n'
'800000 8690\n700000 5105\n600000 3800\n500000 5131\n400000 5479\n'
'300000 7571\n200000 133618'
}
final_freq = {
'cpu0': '1700000 7159\n1600000 0\n1500000 0\n1400000 68\n1300000 134\n'
'1200000 194\n1100000 296\n1000000 716\n900000 1301\n800000 851\n'
'700000 554\n600000 343\n500000 612\n400000 691\n300000 855\n'
'200000 15525',
'cpu1': '1700000 12048\n1600000 0\n1500000 0\n1400000 280\n1300000 1267\n'
'1200000 2272\n1100000 3163\n1000000 7039\n900000 13800\n'
'800000 9599\n700000 5655\n600000 4144\n500000 5655\n400000 6005\n'
'300000 8288\n200000 149724'
}
expected_initial_freq = {
'cpu0': {
1700000000: 6227,
1600000000: 0,
1500000000: 0,
1400000000: 28,
1300000000: 22,
1200000000: 14,
1100000000: 19,
1000000000: 22,
900000000: 14,
800000000: 20,
700000000: 15,
600000000: 23,
500000000: 23,
400000000: 9,
300000000: 28,
200000000: 179
},
'cpu1': {
1700000000: 11491,
1600000000: 0,
1500000000: 0,
1400000000: 248,
1300000000: 1166,
1200000000: 2082,
1100000000: 2943,
1000000000: 6560,
900000000: 12517,
800000000: 8690,
700000000: 5105,
600000000: 3800,
500000000: 5131,
400000000: 5479,
300000000: 7571,
200000000: 133618
}
}
expected_final_freq = {
'cpu0': {
1700000000: 7159,
1600000000: 0,
1500000000: 0,
1400000000: 68,
1300000000: 134,
1200000000: 194,
1100000000: 296,
1000000000: 716,
900000000: 1301,
800000000: 851,
700000000: 554,
600000000: 343,
500000000: 612,
400000000: 691,
300000000: 855,
200000000: 15525
},
'cpu1': {
1700000000: 12048,
1600000000: 0,
1500000000: 0,
1400000000: 280,
1300000000: 1267,
1200000000: 2272,
1100000000: 3163,
1000000000: 7039,
900000000: 13800,
800000000: 9599,
700000000: 5655,
600000000: 4144,
500000000: 5655,
400000000: 6005,
300000000: 8288,
200000000: 149724
}
}
expected_freq_percents = {
'whole_package': {
1700000000: 3.29254111574526,
1600000000: 0.0,
1500000000: 0.0,
1400000000: 0.15926805099535601,
1300000000: 0.47124116307273645,
1200000000: 0.818756100807525,
1100000000: 1.099381692400982,
1000000000: 2.5942528544384302,
900000000: 5.68661122326737,
800000000: 3.850545467654628,
700000000: 2.409691872245393,
600000000: 1.4693702487650486,
500000000: 2.4623575553879373,
400000000: 2.672038150383057,
300000000: 3.415770495015825,
200000000: 69.59817400982045
},
'cpu0': {
1700000000: 4.113700564971752,
1600000000: 0.0,
1500000000: 0.0,
1400000000: 0.1765536723163842,
1300000000: 0.4943502824858757,
1200000000: 0.7944915254237288,
1100000000: 1.2226341807909604,
1000000000: 3.0632062146892656,
900000000: 5.680614406779661,
800000000: 3.6679025423728815,
700000000: 2.379060734463277,
600000000: 1.4124293785310735,
500000000: 2.599752824858757,
400000000: 3.0102401129943503,
300000000: 3.650247175141243,
200000000: 67.73481638418079
},
'cpu1': {
1700000000: 2.4713816665187682,
1600000000: 0.0,
1500000000: 0.0,
1400000000: 0.1419824296743278,
1300000000: 0.44813204365959713,
1200000000: 0.8430206761913214,
1100000000: 0.9761292040110037,
1000000000: 2.1252994941875945,
900000000: 5.69260803975508,
800000000: 4.033188392936374,
700000000: 2.4403230100275093,
600000000: 1.526311118999024,
500000000: 2.3249622859171177,
400000000: 2.3338361877717633,
300000000: 3.1812938148904073,
200000000: 71.46153163546012
}
}
def testParseCpuFreq(self):
initial = sysfs_power_monitor.SysfsPowerMonitor.ParseFreqSample(
self.initial_freq)
final = sysfs_power_monitor.SysfsPowerMonitor.ParseFreqSample(
self.final_freq)
self.assertDictEqual(initial, self.expected_initial_freq)
self.assertDictEqual(final, self.expected_final_freq)
def testComputeCpuStats(self):
results = sysfs_power_monitor.SysfsPowerMonitor.ComputeCpuStats(
self.expected_initial_freq, self.expected_final_freq)
for cpu in results:
for freq in results[cpu]:
self.assertAlmostEqual(results[cpu][freq],
self.expected_freq_percents[cpu][freq])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment