- add sources.
[platform/framework/web/crosswalk.git] / src / build / util / lib / common / perf_tests_results_helper.py
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 _MeanAndStdDevFromList(values):
67   avg = None
68   sd = None
69   if len(values) > 1:
70     try:
71       value = '[%s]' % ','.join([str(v) for v in values])
72       avg = sum([float(v) for v in values]) / len(values)
73       sqdiffs = [(float(v) - avg) ** 2 for v in values]
74       variance = sum(sqdiffs) / (len(values) - 1)
75       sd = math.sqrt(variance)
76     except ValueError:
77       value = ", ".join(values)
78   else:
79     value = values[0]
80   return value, avg, sd
81
82
83 def PrintPages(page_list):
84   """Prints list of pages to stdout in the format required by perf tests."""
85   print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list])
86
87
88 def PrintPerfResult(measurement, trace, values, units,
89                     result_type=perf_result_data_type.DEFAULT,
90                     print_to_stdout=True):
91   """Prints numerical data to stdout in the format required by perf tests.
92
93   The string args may be empty but they must not contain any colons (:) or
94   equals signs (=).
95   This is parsed by the buildbot using:
96   http://src.chromium.org/viewvc/chrome/trunk/tools/build/scripts/slave/process_log_utils.py
97
98   Args:
99     measurement: A description of the quantity being measured, e.g. "vm_peak".
100         On the dashboard, this maps to a particular graph. Mandatory.
101     trace: A description of the particular data point, e.g. "reference".
102         On the dashboard, this maps to a particular "line" in the graph.
103         Mandatory.
104     values: A list of numeric measured values. An N-dimensional list will be
105         flattened and treated as a simple list.
106     units: A description of the units of measure, e.g. "bytes".
107     result_type: Accepts values of perf_result_data_type.ALL_TYPES.
108     print_to_stdout: If True, prints the output in stdout instead of returning
109         the output to caller.
110
111     Returns:
112       String of the formated perf result.
113   """
114   assert perf_result_data_type.IsValidType(result_type), \
115          'result type: %s is invalid' % result_type
116
117   trace_name = _EscapePerfResult(trace)
118
119   if (result_type == perf_result_data_type.UNIMPORTANT or
120       result_type == perf_result_data_type.DEFAULT or
121       result_type == perf_result_data_type.INFORMATIONAL):
122     assert isinstance(values, list)
123     assert '/' not in measurement
124     flattened_values = FlattenList(values)
125     assert len(flattened_values)
126     value, avg, sd = _MeanAndStdDevFromList(flattened_values)
127     output = '%s%s: %s%s%s %s' % (
128         RESULT_TYPES[result_type],
129         _EscapePerfResult(measurement),
130         trace_name,
131         # Do not show equal sign if the trace is empty. Usually it happens when
132         # measurement is enough clear to describe the result.
133         '= ' if trace_name else '',
134         value,
135         units)
136   else:
137     assert perf_result_data_type.IsHistogram(result_type)
138     assert isinstance(values, list)
139     # The histograms can only be printed individually, there's no computation
140     # across different histograms.
141     assert len(values) == 1
142     value = values[0]
143     output = '%s%s: %s= %s %s' % (
144         RESULT_TYPES[result_type],
145         _EscapePerfResult(measurement),
146         trace_name,
147         value,
148         units)
149     avg, sd = GeomMeanAndStdDevFromHistogram(value)
150
151   if avg:
152     output += '\nAvg %s: %f%s' % (measurement, avg, units)
153   if sd:
154     output += '\nSd  %s: %f%s' % (measurement, sd, units)
155   if print_to_stdout:
156     print output
157     sys.stdout.flush()
158   return output