| Index: build/util/lib/common/perf_tests_results_helper.py
|
| diff --git a/build/util/lib/common/perf_tests_results_helper.py b/build/util/lib/common/perf_tests_results_helper.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6cb058b2df37a5e20034312cf9dca816d6fc0045
|
| --- /dev/null
|
| +++ b/build/util/lib/common/perf_tests_results_helper.py
|
| @@ -0,0 +1,166 @@
|
| +# Copyright 2013 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 re
|
| +import sys
|
| +
|
| +import json
|
| +import logging
|
| +import math
|
| +
|
| +import perf_result_data_type
|
| +
|
| +
|
| +# Mapping from result type to test output
|
| +RESULT_TYPES = {perf_result_data_type.UNIMPORTANT: 'RESULT ',
|
| + perf_result_data_type.DEFAULT: '*RESULT ',
|
| + perf_result_data_type.INFORMATIONAL: '',
|
| + perf_result_data_type.UNIMPORTANT_HISTOGRAM: 'HISTOGRAM ',
|
| + perf_result_data_type.HISTOGRAM: '*HISTOGRAM '}
|
| +
|
| +
|
| +def _EscapePerfResult(s):
|
| + """Escapes |s| for use in a perf result."""
|
| + return re.sub('[\:|=/#&,]', '_', s)
|
| +
|
| +
|
| +def FlattenList(values):
|
| + """Returns a simple list without sub-lists."""
|
| + ret = []
|
| + for entry in values:
|
| + if isinstance(entry, list):
|
| + ret.extend(FlattenList(entry))
|
| + else:
|
| + ret.append(entry)
|
| + return ret
|
| +
|
| +
|
| +def GeomMeanAndStdDevFromHistogram(histogram_json):
|
| + histogram = json.loads(histogram_json)
|
| + # Handle empty histograms gracefully.
|
| + if not 'buckets' in histogram:
|
| + return 0.0, 0.0
|
| + count = 0
|
| + sum_of_logs = 0
|
| + for bucket in histogram['buckets']:
|
| + if 'high' in bucket:
|
| + bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0
|
| + else:
|
| + bucket['mean'] = bucket['low']
|
| + if bucket['mean'] > 0:
|
| + sum_of_logs += math.log(bucket['mean']) * bucket['count']
|
| + count += bucket['count']
|
| +
|
| + if count == 0:
|
| + return 0.0, 0.0
|
| +
|
| + sum_of_squares = 0
|
| + geom_mean = math.exp(sum_of_logs / count)
|
| + for bucket in histogram['buckets']:
|
| + if bucket['mean'] > 0:
|
| + sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count']
|
| + return geom_mean, math.sqrt(sum_of_squares / count)
|
| +
|
| +
|
| +def _ValueToString(v):
|
| + # Special case for floats so we don't print using scientific notation.
|
| + if isinstance(v, float):
|
| + return '%f' % v
|
| + else:
|
| + return str(v)
|
| +
|
| +
|
| +def _MeanAndStdDevFromList(values):
|
| + avg = None
|
| + sd = None
|
| + if len(values) > 1:
|
| + try:
|
| + value = '[%s]' % ','.join([_ValueToString(v) for v in values])
|
| + avg = sum([float(v) for v in values]) / len(values)
|
| + sqdiffs = [(float(v) - avg) ** 2 for v in values]
|
| + variance = sum(sqdiffs) / (len(values) - 1)
|
| + sd = math.sqrt(variance)
|
| + except ValueError:
|
| + value = ', '.join(values)
|
| + else:
|
| + value = values[0]
|
| + return value, avg, sd
|
| +
|
| +
|
| +def PrintPages(page_list):
|
| + """Prints list of pages to stdout in the format required by perf tests."""
|
| + print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list])
|
| +
|
| +
|
| +def PrintPerfResult(measurement, trace, values, units,
|
| + result_type=perf_result_data_type.DEFAULT,
|
| + print_to_stdout=True):
|
| + """Prints numerical data to stdout in the format required by perf tests.
|
| +
|
| + The string args may be empty but they must not contain any colons (:) or
|
| + equals signs (=).
|
| + This is parsed by the buildbot using:
|
| + http://src.chromium.org/viewvc/chrome/trunk/tools/build/scripts/slave/process_log_utils.py
|
| +
|
| + Args:
|
| + measurement: A description of the quantity being measured, e.g. "vm_peak".
|
| + On the dashboard, this maps to a particular graph. Mandatory.
|
| + trace: A description of the particular data point, e.g. "reference".
|
| + On the dashboard, this maps to a particular "line" in the graph.
|
| + Mandatory.
|
| + values: A list of numeric measured values. An N-dimensional list will be
|
| + flattened and treated as a simple list.
|
| + units: A description of the units of measure, e.g. "bytes".
|
| + result_type: Accepts values of perf_result_data_type.ALL_TYPES.
|
| + print_to_stdout: If True, prints the output in stdout instead of returning
|
| + the output to caller.
|
| +
|
| + Returns:
|
| + String of the formated perf result.
|
| + """
|
| + assert perf_result_data_type.IsValidType(result_type), \
|
| + 'result type: %s is invalid' % result_type
|
| +
|
| + trace_name = _EscapePerfResult(trace)
|
| +
|
| + if (result_type == perf_result_data_type.UNIMPORTANT or
|
| + result_type == perf_result_data_type.DEFAULT or
|
| + result_type == perf_result_data_type.INFORMATIONAL):
|
| + assert isinstance(values, list)
|
| + assert '/' not in measurement
|
| + flattened_values = FlattenList(values)
|
| + assert len(flattened_values)
|
| + value, avg, sd = _MeanAndStdDevFromList(flattened_values)
|
| + output = '%s%s: %s%s%s %s' % (
|
| + RESULT_TYPES[result_type],
|
| + _EscapePerfResult(measurement),
|
| + trace_name,
|
| + # Do not show equal sign if the trace is empty. Usually it happens when
|
| + # measurement is enough clear to describe the result.
|
| + '= ' if trace_name else '',
|
| + value,
|
| + units)
|
| + else:
|
| + assert perf_result_data_type.IsHistogram(result_type)
|
| + assert isinstance(values, list)
|
| + # The histograms can only be printed individually, there's no computation
|
| + # across different histograms.
|
| + assert len(values) == 1
|
| + value = values[0]
|
| + output = '%s%s: %s= %s %s' % (
|
| + RESULT_TYPES[result_type],
|
| + _EscapePerfResult(measurement),
|
| + trace_name,
|
| + value,
|
| + units)
|
| + avg, sd = GeomMeanAndStdDevFromHistogram(value)
|
| +
|
| + if avg:
|
| + output += '\nAvg %s: %f%s' % (measurement, avg, units)
|
| + if sd:
|
| + output += '\nSd %s: %f%s' % (measurement, sd, units)
|
| + if print_to_stdout:
|
| + print output
|
| + sys.stdout.flush()
|
| + return output
|
|
|