Skip to content

Commit

Permalink
Bug 1578487 - Add frequency and watts metric to mozpower IPG output. …
Browse files Browse the repository at this point in the history
…r=stephendonner

This patch adds GPU and CPU clock frequencies as well as Watts used to the metrics that are gathered into perfherder from mozpower.

Differential Revision: https://phabricator.services.mozilla.com/D50522

--HG--
extra : moz-landing-system : lando
  • Loading branch information
Gregory Mierzwinski committed Oct 31, 2019
1 parent 1ba5593 commit 8fd3e10
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 17 deletions.
67 changes: 63 additions & 4 deletions testing/mozbase/mozpower/mozpower/intel_power_gadget.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,13 @@ def replace_measure_name(name):
:returns: str
"""
lname = name.lower()
if ' ia ' in lname:
if 'ia ' in lname:
return 'processor-cores'
elif ' processor ' in lname:
elif 'processor ' in lname:
return 'processor-package'
elif ' gt ' in lname:
elif 'gt ' in lname:
return 'gpu'
elif ' dram ' in lname:
elif 'dram ' in lname:
return 'dram'
else:
return name
Expand All @@ -787,6 +787,19 @@ def replace_measure_name(name):
cut_results[measure][-1]
)

# Get the power usage rate in Watts
watt_usage = {}
for measure in cut_results:
if 'watt' in measure.lower() and 'limit' not in measure.lower():
watt_usage[replace_measure_name(measure) + '-avg'] = sum([
float(val)
for val in cut_results[measure]
])/len(cut_results[measure])
watt_usage[replace_measure_name(measure) + '-max'] = max([
float(val)
for val in cut_results[measure]
])

# Get average CPU and GPU utilization
average_utilization = {}
for utilization in ('CPU Utilization(%)', 'GT Utilization(%)'):
Expand All @@ -805,6 +818,34 @@ def replace_measure_name(name):
for val in cut_results[utilization]
])/len(cut_results[utilization])

# Get average and maximum CPU and GPU frequency
frequency_info = {'cpu': {}, 'gpu': {}}
for frequency_measure in ('CPU Frequency_0(MHz)', 'GT Frequency(MHz)'):
if frequency_measure not in cut_results:
self._logger.warning("Could not find measurements for: %s" % frequency_measure)
continue

fmeasure_name = frequency_measure.lower()
if 'cpu ' in fmeasure_name:
fmeasure_name = 'cpu'
elif 'gt ' in fmeasure_name:
fmeasure_name = 'gpu'

frequency_info[fmeasure_name]['favg'] = sum([
float(val)
for val in cut_results[frequency_measure]
])/len(cut_results[frequency_measure])

frequency_info[fmeasure_name]['fmax'] = max([
float(val)
for val in cut_results[frequency_measure]
])

frequency_info[fmeasure_name]['fmin'] = min([
float(val)
for val in cut_results[frequency_measure]
])

summarized_results = {
"utilization": {
"type": "power",
Expand All @@ -817,6 +858,24 @@ def replace_measure_name(name):
"test": str(test_name) + '-cumulative',
"unit": "mWh",
"values": cumulative_mwh
},
"power-watts": {
"type": "power",
"test": str(test_name) + '-watts',
"unit": "W",
"values": watt_usage
},
"frequency-cpu": {
"type": "power",
"test": str(test_name) + '-frequency-cpu',
"unit": "MHz",
"values": frequency_info['cpu']
},
"frequency-gpu": {
"type": "power",
"test": str(test_name) + '-frequency-gpu',
"unit": "MHz",
"values": frequency_info['gpu']
}
}

Expand Down
6 changes: 5 additions & 1 deletion testing/mozbase/mozpower/mozpower/mozpower.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .macintelpower import MacIntelPower
from .mozpowerutils import (
average_summary,
frequency_summary,
get_logger,
sum_summary
)
Expand All @@ -22,6 +23,9 @@
SUMMARY_METHODS = {
'utilization': average_summary,
'power-usage': sum_summary,
'power-watts': frequency_summary,
'frequency-cpu': frequency_summary,
'frequency-gpu': frequency_summary,
'default': sum_summary
}

Expand Down Expand Up @@ -367,7 +371,7 @@ def get_full_perfherder_data(self, framework, lowerisbetter=True, alertthreshold
'alertThreshold': alertthreshold,
'unit': settings['unit']
}
values.append(value)
values.append((value, measure))
subtests.append(subtest)

# Summarize the data based on the measurement type
Expand Down
18 changes: 16 additions & 2 deletions testing/mozbase/mozpower/mozpower/mozpowerutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def average_summary(values):
:param list values: list of values to average.
:returns: float
"""
return sum([float(v) for v in values])/len(values)
return sum([float(v[0]) for v in values])/len(values)


def sum_summary(values):
Expand All @@ -39,4 +39,18 @@ def sum_summary(values):
:param list values: list of values to sum.
:returns: float
"""
return sum([float(v) for v in values])
return sum([float(v[0]) for v in values])


def frequency_summary(values):
"""Returns the average frequency as the summary value.
:param list values: list of values to search in.
:returns: float
"""
avgfreq = 0
for val, name in values:
if 'avg' in name:
avgfreq = float(val)
break
return avgfreq
21 changes: 19 additions & 2 deletions testing/mozbase/mozpower/tests/test_intelpowergadget.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,28 @@ def test_ipg_rh_format_to_perfherder_without_cutoff(ipg_rh_obj):
)

# Check that the expected entries exist
assert len(formatted_data.keys()) == 2
assert len(formatted_data.keys()) == 5
assert 'utilization' in formatted_data and 'power-usage' in formatted_data
assert formatted_data['power-usage']['test'] == ipg_rh_obj._output_file_prefix + '-cumulative'

assert formatted_data['power-usage']['test'] == \
ipg_rh_obj._output_file_prefix + '-cumulative'
assert formatted_data['utilization']['test'] == \
ipg_rh_obj._output_file_prefix + '-utilization'
assert formatted_data['frequency-gpu']['test'] == \
ipg_rh_obj._output_file_prefix + '-frequency-gpu'
assert formatted_data['frequency-cpu']['test'] == \
ipg_rh_obj._output_file_prefix + '-frequency-cpu'
assert formatted_data['power-watts']['test'] == \
ipg_rh_obj._output_file_prefix + '-watts'

for measure in formatted_data:
# Make sure that the data exists
assert len(formatted_data[measure]['values']) >= 1

for valkey in formatted_data[measure]['values']:
# Make sure the names were simplified
assert '(' not in valkey
assert ')' not in valkey

# Check that gpu utilization doesn't exist but cpu does
utilization_vals = formatted_data['utilization']['values']
Expand Down
40 changes: 39 additions & 1 deletion testing/mozbase/mozpower/tests/test_mozpower.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,32 @@ def test_mozpower_get_full_perfherder_data(mozpower_obj):
'dram': 0.1,
'gpu': 4.0
}
},
'frequency-cpu': {
'type': 'power',
'test': 'mozpower',
'unit': 'MHz',
'values': {
'cpu-favg': 2.0,
'cpu-fmax': 5.0,
'cpu-fmin': 0.0,
}
},
'frequency-gpu': {
'type': 'power',
'test': 'mozpower',
'unit': 'MHz',
'values': {
'gpu-favg': 3.0,
'gpu-fmax': 6.0,
'gpu-fmin': 0.0
}
}
}
utilization_vals = [0, 50]
power_usage_vals = [2.0, 0.1, 4.0]
frequency_cpu_vals = [2.0, 5.0, 0.0]
frequency_gpu_vals = [3.0, 6.0, 0.0]

with mock.patch(
'mozpower.macintelpower.MacIntelPower.get_perfherder_data'
Expand All @@ -199,7 +221,7 @@ def test_mozpower_get_full_perfherder_data(mozpower_obj):

full_perfherder = mozpower_obj.get_full_perfherder_data('mozpower')
assert full_perfherder['framework']['name'] == 'mozpower'
assert len(full_perfherder['suites']) == 2
assert len(full_perfherder['suites']) == 4

# Check that each of the two suites were created correctly.
suites = full_perfherder['suites']
Expand All @@ -219,6 +241,10 @@ def test_mozpower_get_full_perfherder_data(mozpower_obj):
assert 'utilization' in subtest['name']
elif 'power-usage' in suite['name']:
assert 'power-usage' in subtest['name']
elif 'frequency-cpu' in suite['name']:
assert 'frequency-cpu' in subtest['name']
elif 'frequency-gpu' in suite['name']:
assert 'frequency-gpu' in subtest['name']
else:
assert False, "Unknown subtest name %s" % subtest['name']

Expand All @@ -236,6 +262,18 @@ def test_mozpower_get_full_perfherder_data(mozpower_obj):
assert suite['name'] == 'mozpower-power-usage'
assert not list(set(all_vals) - set(power_usage_vals))
assert suite['value'] == float(6.1)
elif 'frequency-cpu' in suite['name']:
assert len(all_vals) == 3
assert suite['unit'] == 'MHz'
assert suite['name'] == 'mozpower-frequency-cpu'
assert not list(set(all_vals) - set(frequency_cpu_vals))
assert suite['value'] == float(2.0)
elif 'frequency-gpu' in suite['name']:
assert len(all_vals) == 3
assert suite['unit'] == 'MHz'
assert suite['name'] == 'mozpower-frequency-gpu'
assert not list(set(all_vals) - set(frequency_gpu_vals))
assert suite['value'] == float(3.0)
else:
assert False, "Unknown suite name %s" % suite['name']

Expand Down
19 changes: 14 additions & 5 deletions testing/raptor/raptor/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def _filter(vals, value=None):
results = results[75::76]
return 60 * 1000 / filters.geometric_mean(results) / correctionFactor

if testname.startswith(('raptor-kraken', 'raptor-sunspider', 'supporting_data')):
if testname.startswith(('raptor-kraken', 'raptor-sunspider')):
return sum(_filter(vals))

if testname.startswith(('raptor-unity-webgl', 'raptor-webaudio')):
Expand All @@ -335,10 +335,19 @@ def _filter(vals, value=None):
return round(filters.mean(_filter(vals)), 2)

if testname.startswith('supporting_data'):
if unit and unit in ('%',):
return filters.mean(_filter(vals))
else:
return sum(_filter(vals))
if unit:
if unit in ('%',):
return filters.mean(_filter(vals))
elif unit in ('W', 'MHz'):
# For power in Watts and clock frequencies,
# summarize with the sum of the averages
allavgs = []
for (val, subtest) in vals:
if 'avg' in subtest:
allavgs.append(val)
if allavgs:
return sum(allavgs)
return sum(_filter(vals))

if len(vals) > 1:
return round(filters.geometric_mean(_filter(vals)), 2)
Expand Down
6 changes: 4 additions & 2 deletions testing/raptor/raptor/raptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -834,8 +834,10 @@ def run_test(self, test, timeout):
shutil.make_archive(power_data_path, 'zip', power_data_path)
shutil.rmtree(power_data_path)

self.control_server.submit_supporting_data(perfherder_data['utilization'])
self.control_server.submit_supporting_data(perfherder_data['power-usage'])
for data_type in perfherder_data:
self.control_server.submit_supporting_data(
perfherder_data[data_type]
)

def __run_test_cold(self, test, timeout):
'''
Expand Down

0 comments on commit 8fd3e10

Please sign in to comment.