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 re | |
6 import sys | |
7 | |
8 import json | |
9 import logging | |
10 import math | |
11 | |
12 | |
13 sys.path.append( | |
14 os.path.abspath(os.path.join(os.path.dirname(__file__), | |
15 os.pardir, os.pardir, os.pardir, | |
16 'tools', 'telemetry'))) | |
17 | |
18 from telemetry.page import result_data_type | |
bulach
2013/09/11 11:41:07
can we define the result_data_type here rather tha
| |
19 | |
20 | |
21 # Mapping from result type to test output | |
22 RESULT_TYPES = {result_data_type.UNIMPORTANT: 'RESULT ', | |
23 result_data_type.DEFAULT: '*RESULT ', | |
24 result_data_type.INFORMATIONAL: '', | |
25 result_data_type.UNIMPORTANT_HISTOGRAM: 'HISTOGRAM ', | |
26 result_data_type.HISTOGRAM: '*HISTOGRAM '} | |
27 | |
28 def _EscapePerfResult(s): | |
29 """Escapes |s| for use in a perf result.""" | |
30 return re.sub('[\:|=/#&,]', '_', s) | |
31 | |
32 | |
33 def _Flatten(values): | |
34 """Returns a simple list without sub-lists.""" | |
35 ret = [] | |
36 for entry in values: | |
37 if isinstance(entry, list): | |
38 ret.extend(_Flatten(entry)) | |
39 else: | |
40 ret.append(entry) | |
41 return ret | |
42 | |
43 | |
44 def GeomMeanAndStdDevFromHistogram(histogram_json): | |
45 histogram = json.loads(histogram_json) | |
46 # Handle empty histograms gracefully. | |
47 if not 'buckets' in histogram: | |
48 return 0.0, 0.0 | |
49 count = 0 | |
50 sum_of_logs = 0 | |
51 for bucket in histogram['buckets']: | |
52 if 'high' in bucket: | |
53 bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0 | |
54 else: | |
55 bucket['mean'] = bucket['low'] | |
56 if bucket['mean'] > 0: | |
57 sum_of_logs += math.log(bucket['mean']) * bucket['count'] | |
58 count += bucket['count'] | |
59 | |
60 if count == 0: | |
61 return 0.0, 0.0 | |
62 | |
63 sum_of_squares = 0 | |
64 geom_mean = math.exp(sum_of_logs / count) | |
65 for bucket in histogram['buckets']: | |
66 if bucket['mean'] > 0: | |
67 sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count'] | |
68 return geom_mean, math.sqrt(sum_of_squares / count) | |
69 | |
70 | |
71 def _MeanAndStdDevFromList(values): | |
72 avg = None | |
73 sd = None | |
74 if len(values) > 1: | |
75 try: | |
76 value = '[%s]' % ','.join([str(v) for v in values]) | |
77 avg = sum([float(v) for v in values]) / len(values) | |
78 sqdiffs = [(float(v) - avg) ** 2 for v in values] | |
79 variance = sum(sqdiffs) / (len(values) - 1) | |
80 sd = math.sqrt(variance) | |
81 except ValueError: | |
82 value = ", ".join(values) | |
83 else: | |
84 value = values[0] | |
85 return value, avg, sd | |
86 | |
87 | |
88 def PrintPages(page_list): | |
89 """Prints list of pages to stdout in the format required by perf tests.""" | |
90 print 'Pages: [%s]' % ','.join([_EscapePerfResult(p) for p in page_list]) | |
91 | |
92 | |
93 def PrintPerfResult(measurement, trace, values, units, | |
94 result_type=result_data_type.DEFAULT, | |
95 print_to_stdout=True): | |
96 """Prints numerical data to stdout in the format required by perf tests. | |
97 | |
98 The string args may be empty but they must not contain any colons (:) or | |
99 equals signs (=). | |
100 | |
101 Args: | |
102 measurement: A description of the quantity being measured, e.g. "vm_peak". | |
103 trace: A description of the particular data point, e.g. "reference". | |
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 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 (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 == result_data_type.UNIMPORTANT or | |
120 result_type == result_data_type.DEFAULT or | |
121 result_type == result_data_type.INFORMATIONAL): | |
122 assert isinstance(values, list) | |
123 assert len(values) | |
124 assert '/' not in measurement | |
125 value, avg, sd = _MeanAndStdDevFromList(_Flatten(values)) | |
126 output = '%s%s: %s%s%s %s' % ( | |
127 RESULT_TYPES[result_type], | |
128 _EscapePerfResult(measurement), | |
129 trace_name, | |
130 # Do not show equal sign if the trace is empty. Usually it happens when | |
131 # measurement is enough clear to describe the result. | |
132 '= ' if trace_name else '', | |
133 value, | |
134 units) | |
135 else: | |
136 assert result_data_type.IsHistogram(result_type) | |
137 assert isinstance(values, list) | |
138 # The histograms can only be printed individually, there's no computation | |
139 # across different histograms. | |
140 assert len(values) == 1 | |
141 value = values[0] | |
142 output = '%s%s: %s= %s' % ( | |
143 RESULT_TYPES[result_type], | |
144 _EscapePerfResult(measurement), | |
145 trace_name, | |
146 value) | |
147 avg, sd = GeomMeanAndStdDevFromHistogram(value) | |
148 | |
149 if avg: | |
150 output += '\nAvg %s: %f%s' % (measurement, avg, units) | |
151 if sd: | |
152 output += '\nSd %s: %f%s' % (measurement, sd, units) | |
153 if print_to_stdout: | |
154 print output | |
155 sys.stdout.flush() | |
156 return output | |
157 | |
158 | |
159 class CacheControl(object): | |
bulach
2013/09/11 11:41:07
could you remove both CacheControl and PerfControl
| |
160 _DROP_CACHES = '/proc/sys/vm/drop_caches' | |
161 | |
162 def __init__(self, adb): | |
163 self._adb = adb | |
164 | |
165 def DropRamCaches(self): | |
166 """Drops the filesystem ram caches for performance testing.""" | |
167 self._adb.RunShellCommand('su -c sync') | |
168 self._adb.SetProtectedFileContents(CacheControl._DROP_CACHES, '3') | |
169 | |
170 | |
171 class PerfControl(object): | |
172 """Provides methods for setting the performance mode of a device.""" | |
173 _SCALING_GOVERNOR_FMT = ( | |
174 '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') | |
175 | |
176 def __init__(self, adb): | |
177 self._adb = adb | |
178 kernel_max = self._adb.GetFileContents('/sys/devices/system/cpu/kernel_max', | |
179 log_result=False) | |
180 assert kernel_max, 'Unable to find /sys/devices/system/cpu/kernel_max' | |
181 self._kernel_max = int(kernel_max[0]) | |
182 logging.info('Maximum CPU index: %d' % self._kernel_max) | |
183 self._original_scaling_governor = self._adb.GetFileContents( | |
184 PerfControl._SCALING_GOVERNOR_FMT % 0, | |
185 log_result=False)[0] | |
186 | |
187 def SetHighPerfMode(self): | |
188 """Sets the highest possible performance mode for the device.""" | |
189 self._SetScalingGovernorInternal('performance') | |
190 | |
191 def SetDefaultPerfMode(self): | |
192 """Sets the performance mode for the device to its default mode.""" | |
193 product_model = self._adb.GetProductModel() | |
194 governor_mode = { | |
195 "GT-I9300" : 'pegasusq', | |
196 "Galaxy Nexus" : 'interactive', | |
197 "Nexus 4" : 'ondemand', | |
198 "Nexus 7" : 'interactive', | |
199 "Nexus 10": 'interactive' | |
200 }.get(product_model, 'ondemand') | |
201 self._SetScalingGovernorInternal(governor_mode) | |
202 | |
203 def RestoreOriginalPerfMode(self): | |
204 """Resets the original performance mode of the device.""" | |
205 self._SetScalingGovernorInternal(self._original_scaling_governor) | |
206 | |
207 def _SetScalingGovernorInternal(self, value): | |
208 for cpu in range(self._kernel_max + 1): | |
209 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu | |
210 if self._adb.FileExistsOnDevice(scaling_governor_file): | |
211 logging.info('Writing scaling governor mode \'%s\' -> %s' % | |
212 (value, scaling_governor_file)) | |
213 self._adb.SetProtectedFileContents(scaling_governor_file, value) | |
OLD | NEW |