Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / build / util / lib / common / perf_tests_results_helper.py
blob6cb058b2df37a5e20034312cf9dca816d6fc0045
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.
5 import re
6 import sys
8 import json
9 import logging
10 import math
12 import perf_result_data_type
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 '}
23 def _EscapePerfResult(s):
24 """Escapes |s| for use in a perf result."""
25 return re.sub('[\:|=/#&,]', '_', s)
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
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']
55 if count == 0:
56 return 0.0, 0.0
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)
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)
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
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])
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.
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
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.
119 Returns:
120 String of the formated perf result.
122 assert perf_result_data_type.IsValidType(result_type), \
123 'result type: %s is invalid' % result_type
125 trace_name = _EscapePerfResult(trace)
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)
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