OLD | NEW |
| (Empty) |
1 # Copyright (c) 2012 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 json | |
6 import logging | |
7 import math | |
8 import re | |
9 import sys | |
10 | |
11 import android_commands | |
12 | |
13 from perf import cache_control | |
14 from perf import perf_control | |
15 | |
16 | |
17 # Valid values of result type. | |
18 RESULT_TYPES = {'unimportant': 'RESULT ', | |
19 'default': '*RESULT ', | |
20 'informational': '', | |
21 'unimportant-histogram': 'HISTOGRAM ', | |
22 'histogram': '*HISTOGRAM '} | |
23 | |
24 | |
25 def _EscapePerfResult(s): | |
26 """Escapes |s| for use in a perf result.""" | |
27 return re.sub('[\:|=/#&,]', '_', s) | |
28 | |
29 | |
30 def _Flatten(values): | |
31 """Returns a simple list without sub-lists.""" | |
32 ret = [] | |
33 for entry in values: | |
34 if isinstance(entry, list): | |
35 ret.extend(_Flatten(entry)) | |
36 else: | |
37 ret.append(entry) | |
38 return ret | |
39 | |
40 | |
41 def GeomMeanAndStdDevFromHistogram(histogram_json): | |
42 histogram = json.loads(histogram_json) | |
43 # Handle empty histograms gracefully. | |
44 if not 'buckets' in histogram: | |
45 return 0.0, 0.0 | |
46 count = 0 | |
47 sum_of_logs = 0 | |
48 for bucket in histogram['buckets']: | |
49 if 'high' in bucket: | |
50 bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0 | |
51 else: | |
52 bucket['mean'] = bucket['low'] | |
53 if bucket['mean'] > 0: | |
54 sum_of_logs += math.log(bucket['mean']) * bucket['count'] | |
55 count += bucket['count'] | |
56 | |
57 if count == 0: | |
58 return 0.0, 0.0 | |
59 | |
60 sum_of_squares = 0 | |
61 geom_mean = math.exp(sum_of_logs / count) | |
62 for bucket in histogram['buckets']: | |
63 if bucket['mean'] > 0: | |
64 sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count'] | |
65 return geom_mean, math.sqrt(sum_of_squares / count) | |
66 | |
67 | |
68 def _MeanAndStdDevFromList(values): | |
69 avg = None | |
70 sd = None | |
71 if len(values) > 1: | |
72 try: | |
73 value = '[%s]' % ','.join([str(v) for v in values]) | |
74 avg = sum([float(v) for v in values]) / len(values) | |
75 sqdiffs = [(float(v) - avg) ** 2 for v in values] | |
76 variance = sum(sqdiffs) / (len(values) - 1) | |
77 sd = math.sqrt(variance) | |
78 except ValueError: | |
79 value = ", ".join(values) | |
80 else: | |
81 value = values[0] | |
82 return value, avg, sd | |
83 | |
84 | |
85 def PrintPages(page_list): | |
86 """Prints list of pages to stdout in the format required by perf tests.""" | |
87 print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list]) | |
88 | |
89 | |
90 def PrintPerfResult(measurement, trace, values, units, result_type='default', | |
91 print_to_stdout=True): | |
92 """Prints numerical data to stdout in the format required by perf tests. | |
93 | |
94 The string args may be empty but they must not contain any colons (:) or | |
95 equals signs (=). | |
96 | |
97 Args: | |
98 measurement: A description of the quantity being measured, e.g. "vm_peak". | |
99 trace: A description of the particular data point, e.g. "reference". | |
100 values: A list of numeric measured values. An N-dimensional list will be | |
101 flattened and treated as a simple list. | |
102 units: A description of the units of measure, e.g. "bytes". | |
103 result_type: Accepts values of RESULT_TYPES. | |
104 print_to_stdout: If True, prints the output in stdout instead of returning | |
105 the output to caller. | |
106 | |
107 Returns: | |
108 String of the formated perf result. | |
109 """ | |
110 assert result_type in RESULT_TYPES, 'result type: %s is invalid' % result_type | |
111 | |
112 trace_name = _EscapePerfResult(trace) | |
113 | |
114 if result_type in ['unimportant', 'default', 'informational']: | |
115 assert isinstance(values, list) | |
116 assert len(values) | |
117 assert '/' not in measurement | |
118 value, avg, sd = _MeanAndStdDevFromList(_Flatten(values)) | |
119 output = '%s%s: %s%s%s %s' % ( | |
120 RESULT_TYPES[result_type], | |
121 _EscapePerfResult(measurement), | |
122 trace_name, | |
123 # Do not show equal sign if the trace is empty. Usually it happens when | |
124 # measurement is enough clear to describe the result. | |
125 '= ' if trace_name else '', | |
126 value, | |
127 units) | |
128 else: | |
129 assert(result_type in ['histogram', 'unimportant-histogram']) | |
130 assert isinstance(values, list) | |
131 # The histograms can only be printed individually, there's no computation | |
132 # across different histograms. | |
133 assert len(values) == 1 | |
134 value = values[0] | |
135 output = '%s%s: %s= %s %s' % ( | |
136 RESULT_TYPES[result_type], | |
137 _EscapePerfResult(measurement), | |
138 trace_name, | |
139 value, | |
140 units) | |
141 avg, sd = GeomMeanAndStdDevFromHistogram(value) | |
142 | |
143 if avg: | |
144 output += '\nAvg %s: %f%s' % (measurement, avg, units) | |
145 if sd: | |
146 output += '\nSd %s: %f%s' % (measurement, sd, units) | |
147 if print_to_stdout: | |
148 print output | |
149 sys.stdout.flush() | |
150 return output | |
151 | |
152 | |
153 # TODO(bulach): remove once all references to PerfControl are fixed. | |
154 class CacheControl(cache_control.CacheControl): | |
155 def __init__(self, adb): | |
156 super(CacheControl, self).__init__(adb) | |
157 | |
158 class PerfControl(perf_control.PerfControl): | |
159 def __init__(self, adb): | |
160 super(PerfControl, self).__init__(adb) | |
OLD | NEW |