OLD | NEW |
(Empty) | |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import re |
| 6 import sys |
| 7 |
| 8 import json |
| 9 import logging |
| 10 import math |
| 11 |
| 12 import perf_result_data_type |
| 13 |
| 14 |
| 15 # Mapping from result type to test output |
| 16 RESULT_TYPES = {perf_result_data_type.UNIMPORTANT: 'RESULT ', |
| 17 perf_result_data_type.DEFAULT: '*RESULT ', |
| 18 perf_result_data_type.INFORMATIONAL: '', |
| 19 perf_result_data_type.UNIMPORTANT_HISTOGRAM: 'HISTOGRAM ', |
| 20 perf_result_data_type.HISTOGRAM: '*HISTOGRAM '} |
| 21 |
| 22 |
| 23 def _EscapePerfResult(s): |
| 24 """Escapes |s| for use in a perf result.""" |
| 25 return re.sub('[\:|=/#&,]', '_', s) |
| 26 |
| 27 |
| 28 def FlattenList(values): |
| 29 """Returns a simple list without sub-lists.""" |
| 30 ret = [] |
| 31 for entry in values: |
| 32 if isinstance(entry, list): |
| 33 ret.extend(FlattenList(entry)) |
| 34 else: |
| 35 ret.append(entry) |
| 36 return ret |
| 37 |
| 38 |
| 39 def GeomMeanAndStdDevFromHistogram(histogram_json): |
| 40 histogram = json.loads(histogram_json) |
| 41 # Handle empty histograms gracefully. |
| 42 if not 'buckets' in histogram: |
| 43 return 0.0, 0.0 |
| 44 count = 0 |
| 45 sum_of_logs = 0 |
| 46 for bucket in histogram['buckets']: |
| 47 if 'high' in bucket: |
| 48 bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0 |
| 49 else: |
| 50 bucket['mean'] = bucket['low'] |
| 51 if bucket['mean'] > 0: |
| 52 sum_of_logs += math.log(bucket['mean']) * bucket['count'] |
| 53 count += bucket['count'] |
| 54 |
| 55 if count == 0: |
| 56 return 0.0, 0.0 |
| 57 |
| 58 sum_of_squares = 0 |
| 59 geom_mean = math.exp(sum_of_logs / count) |
| 60 for bucket in histogram['buckets']: |
| 61 if bucket['mean'] > 0: |
| 62 sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count'] |
| 63 return geom_mean, math.sqrt(sum_of_squares / count) |
| 64 |
| 65 |
| 66 def _ValueToString(v): |
| 67 # Special case for floats so we don't print using scientific notation. |
| 68 if isinstance(v, float): |
| 69 return '%f' % v |
| 70 else: |
| 71 return str(v) |
| 72 |
| 73 |
| 74 def _MeanAndStdDevFromList(values): |
| 75 avg = None |
| 76 sd = None |
| 77 if len(values) > 1: |
| 78 try: |
| 79 value = '[%s]' % ','.join([_ValueToString(v) for v in values]) |
| 80 avg = sum([float(v) for v in values]) / len(values) |
| 81 sqdiffs = [(float(v) - avg) ** 2 for v in values] |
| 82 variance = sum(sqdiffs) / (len(values) - 1) |
| 83 sd = math.sqrt(variance) |
| 84 except ValueError: |
| 85 value = ', '.join(values) |
| 86 else: |
| 87 value = values[0] |
| 88 return value, avg, sd |
| 89 |
| 90 |
| 91 def PrintPages(page_list): |
| 92 """Prints list of pages to stdout in the format required by perf tests.""" |
| 93 print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list]) |
| 94 |
| 95 |
| 96 def PrintPerfResult(measurement, trace, values, units, |
| 97 result_type=perf_result_data_type.DEFAULT, |
| 98 print_to_stdout=True): |
| 99 """Prints numerical data to stdout in the format required by perf tests. |
| 100 |
| 101 The string args may be empty but they must not contain any colons (:) or |
| 102 equals signs (=). |
| 103 This is parsed by the buildbot using: |
| 104 http://src.chromium.org/viewvc/chrome/trunk/tools/build/scripts/slave/process_
log_utils.py |
| 105 |
| 106 Args: |
| 107 measurement: A description of the quantity being measured, e.g. "vm_peak". |
| 108 On the dashboard, this maps to a particular graph. Mandatory. |
| 109 trace: A description of the particular data point, e.g. "reference". |
| 110 On the dashboard, this maps to a particular "line" in the graph. |
| 111 Mandatory. |
| 112 values: A list of numeric measured values. An N-dimensional list will be |
| 113 flattened and treated as a simple list. |
| 114 units: A description of the units of measure, e.g. "bytes". |
| 115 result_type: Accepts values of perf_result_data_type.ALL_TYPES. |
| 116 print_to_stdout: If True, prints the output in stdout instead of returning |
| 117 the output to caller. |
| 118 |
| 119 Returns: |
| 120 String of the formated perf result. |
| 121 """ |
| 122 assert perf_result_data_type.IsValidType(result_type), \ |
| 123 'result type: %s is invalid' % result_type |
| 124 |
| 125 trace_name = _EscapePerfResult(trace) |
| 126 |
| 127 if (result_type == perf_result_data_type.UNIMPORTANT or |
| 128 result_type == perf_result_data_type.DEFAULT or |
| 129 result_type == perf_result_data_type.INFORMATIONAL): |
| 130 assert isinstance(values, list) |
| 131 assert '/' not in measurement |
| 132 flattened_values = FlattenList(values) |
| 133 assert len(flattened_values) |
| 134 value, avg, sd = _MeanAndStdDevFromList(flattened_values) |
| 135 output = '%s%s: %s%s%s %s' % ( |
| 136 RESULT_TYPES[result_type], |
| 137 _EscapePerfResult(measurement), |
| 138 trace_name, |
| 139 # Do not show equal sign if the trace is empty. Usually it happens when |
| 140 # measurement is enough clear to describe the result. |
| 141 '= ' if trace_name else '', |
| 142 value, |
| 143 units) |
| 144 else: |
| 145 assert perf_result_data_type.IsHistogram(result_type) |
| 146 assert isinstance(values, list) |
| 147 # The histograms can only be printed individually, there's no computation |
| 148 # across different histograms. |
| 149 assert len(values) == 1 |
| 150 value = values[0] |
| 151 output = '%s%s: %s= %s %s' % ( |
| 152 RESULT_TYPES[result_type], |
| 153 _EscapePerfResult(measurement), |
| 154 trace_name, |
| 155 value, |
| 156 units) |
| 157 avg, sd = GeomMeanAndStdDevFromHistogram(value) |
| 158 |
| 159 if avg: |
| 160 output += '\nAvg %s: %f%s' % (measurement, avg, units) |
| 161 if sd: |
| 162 output += '\nSd %s: %f%s' % (measurement, sd, units) |
| 163 if print_to_stdout: |
| 164 print output |
| 165 sys.stdout.flush() |
| 166 return output |
OLD | NEW |