OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import re | 5 import re |
6 | 6 |
7 import android_commands | 7 import android_commands |
| 8 import json |
8 import math | 9 import math |
9 | 10 |
10 # Valid values of result type. | 11 # Valid values of result type. |
11 RESULT_TYPES = {'unimportant': 'RESULT ', | 12 RESULT_TYPES = {'unimportant': 'RESULT ', |
12 'default': '*RESULT ', | 13 'default': '*RESULT ', |
13 'informational': ''} | 14 'informational': '', |
| 15 'unimportant-histogram': 'HISTOGRAM ', |
| 16 'histogram': '*HISTOGRAM '} |
14 | 17 |
15 | 18 |
16 def _EscapePerfResult(s): | 19 def _EscapePerfResult(s): |
17 """Escapes |s| for use in a perf result.""" | 20 """Escapes |s| for use in a perf result.""" |
18 # Colons (:) and equal signs (=) are not allowed, and we chose an arbitrary | 21 # Colons (:) and equal signs (=) are not allowed, and we chose an arbitrary |
19 # limit of 40 chars. | 22 # limit of 40 chars. |
20 return re.sub(':|=', '_', s[:40]) | 23 return re.sub(':|=', '_', s[:40]) |
21 | 24 |
22 | 25 |
| 26 def GeomMeanAndStdDevFromHistogram(histogram_json): |
| 27 histogram = json.loads(histogram_json) |
| 28 count = 0 |
| 29 sum_of_logs = 0 |
| 30 for bucket in histogram['buckets']: |
| 31 if 'high' in bucket: |
| 32 bucket['mean'] = (bucket['low'] + bucket['high']) / 2.0 |
| 33 else: |
| 34 bucket['mean'] = bucket['low'] |
| 35 if bucket['mean'] > 0: |
| 36 sum_of_logs += math.log(bucket['mean']) * bucket['count'] |
| 37 count += bucket['count'] |
| 38 |
| 39 if count == 0: |
| 40 return 0.0, 0.0 |
| 41 |
| 42 sum_of_squares = 0 |
| 43 geom_mean = math.exp(sum_of_logs / count) |
| 44 for bucket in histogram['buckets']: |
| 45 if bucket['mean'] > 0: |
| 46 sum_of_squares += (bucket['mean'] - geom_mean) ** 2 * bucket['count'] |
| 47 return geom_mean, math.sqrt(sum_of_squares / count) |
| 48 |
| 49 |
| 50 def _MeanAndStdDevFromList(values): |
| 51 avg = None |
| 52 sd = None |
| 53 if len(values) > 1: |
| 54 try: |
| 55 value = '[%s]' % ','.join([str(v) for v in values]) |
| 56 avg = sum([float(v) for v in values]) / len(values) |
| 57 sqdiffs = [(float(v) - avg) ** 2 for v in values] |
| 58 variance = sum(sqdiffs) / (len(values) - 1) |
| 59 sd = math.sqrt(variance) |
| 60 except ValueError: |
| 61 value = ", ".join(values) |
| 62 else: |
| 63 value = values[0] |
| 64 return value, avg, sd |
| 65 |
| 66 |
23 def PrintPerfResult(measurement, trace, values, units, result_type='default', | 67 def PrintPerfResult(measurement, trace, values, units, result_type='default', |
24 print_to_stdout=True): | 68 print_to_stdout=True): |
25 """Prints numerical data to stdout in the format required by perf tests. | 69 """Prints numerical data to stdout in the format required by perf tests. |
26 | 70 |
27 The string args may be empty but they must not contain any colons (:) or | 71 The string args may be empty but they must not contain any colons (:) or |
28 equals signs (=). | 72 equals signs (=). |
29 | 73 |
30 Args: | 74 Args: |
31 measurement: A description of the quantity being measured, e.g. "vm_peak". | 75 measurement: A description of the quantity being measured, e.g. "vm_peak". |
32 trace: A description of the particular data point, e.g. "reference". | 76 trace: A description of the particular data point, e.g. "reference". |
33 values: A list of numeric measured values. | 77 values: A list of numeric measured values. |
34 units: A description of the units of measure, e.g. "bytes". | 78 units: A description of the units of measure, e.g. "bytes". |
35 result_type: A tri-state that accepts values of ['unimportant', 'default', | 79 result_type: A tri-state that accepts values of ['unimportant', 'default', |
36 'informational']. 'unimportant' prints RESULT, 'default' prints *RESULT | 80 'informational']. 'unimportant' prints RESULT, 'default' prints *RESULT |
37 and 'informational' prints nothing. | 81 and 'informational' prints nothing. |
38 print_to_stdout: If True, prints the output in stdout instead of returning | 82 print_to_stdout: If True, prints the output in stdout instead of returning |
39 the output to caller. | 83 the output to caller. |
40 | 84 |
41 Returns: | 85 Returns: |
42 String of the formated perf result. | 86 String of the formated perf result. |
43 """ | 87 """ |
44 assert result_type in RESULT_TYPES, 'result type: %s is invalid' % result_type | 88 assert result_type in RESULT_TYPES, 'result type: %s is invalid' % result_type |
45 | 89 |
46 assert isinstance(values, list) | 90 if result_type in ['unimportant', 'default', 'informational']: |
47 assert len(values) | 91 assert isinstance(values, list) |
48 assert '/' not in measurement | 92 assert len(values) |
49 avg = None | 93 assert '/' not in measurement |
50 sd = None | 94 value, avg, sd = _MeanAndStdDevFromList(values) |
51 if len(values) > 1: | |
52 try: | |
53 value = '[%s]' % ','.join([str(v) for v in values]) | |
54 avg = sum([float(v) for v in values]) / len(values) | |
55 sqdiffs = [(float(v) - avg) ** 2 for v in values] | |
56 variance = sum(sqdiffs) / (len(values) - 1) | |
57 sd = math.sqrt(variance) | |
58 except ValueError: | |
59 value = ", ".join(values) | |
60 else: | 95 else: |
61 value = values[0] | 96 value = values[0] |
| 97 # We can't print the units, otherwise parsing the histogram json output |
| 98 # can't be parsed easily. |
| 99 units = '' |
| 100 avg, sd = GeomMeanAndStdDevFromHistogram(value) |
62 | 101 |
63 trace_name = _EscapePerfResult(trace) | 102 trace_name = _EscapePerfResult(trace) |
64 output = '%s%s: %s%s%s %s' % ( | 103 output = '%s%s: %s%s%s %s' % ( |
65 RESULT_TYPES[result_type], | 104 RESULT_TYPES[result_type], |
66 _EscapePerfResult(measurement), | 105 _EscapePerfResult(measurement), |
67 trace_name, | 106 trace_name, |
68 # Do not show equal sign if the trace is empty. Usually it happens when | 107 # Do not show equal sign if the trace is empty. Usually it happens when |
69 # measurement is enough clear to describe the result. | 108 # measurement is enough clear to describe the result. |
70 '= ' if trace_name else '', | 109 '= ' if trace_name else '', |
71 value, | 110 value, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 def TearDown(self): | 150 def TearDown(self): |
112 """Tears down performance tests.""" | 151 """Tears down performance tests.""" |
113 if self._original_scaling_governor: | 152 if self._original_scaling_governor: |
114 self._SetScalingGovernorInternal(self._original_scaling_governor) | 153 self._SetScalingGovernorInternal(self._original_scaling_governor) |
115 self._original_scaling_governor = None | 154 self._original_scaling_governor = None |
116 | 155 |
117 def _SetScalingGovernorInternal(self, value): | 156 def _SetScalingGovernorInternal(self, value): |
118 for cpu in range(self._num_cpus): | 157 for cpu in range(self._num_cpus): |
119 self._adb.RunShellCommand( | 158 self._adb.RunShellCommand( |
120 ('echo %s > ' + PerfTestSetup._SCALING_GOVERNOR) % (value, cpu)) | 159 ('echo %s > ' + PerfTestSetup._SCALING_GOVERNOR) % (value, cpu)) |
OLD | NEW |