Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(616)

Side by Side Diff: bootperf-bin/resultset.py

Issue 4148011: Create bootperf-bin tools for running boot time tests and reporting results (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git
Patch Set: Apply selected fixes recommended by gpylint Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « bootperf-bin/perfprinter.py ('k') | bootperf-bin/showbootdata » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2010 The Chromium OS 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 """Classes and functions for managing platform_BootPerf results.
6
7 Results from the platform_BootPerf test in the ChromiumOS autotest
8 package are stored in as performance 'keyvals', that is, a mapping
9 of names to numeric values. For each iteration of the test, one
10 set of keyvals is recorded.
11
12 This module currently tracks two kinds of keyval results, the boot
13 time results, and the disk read results. These results are stored
14 with keyval names such as 'seconds_kernel_to_login' and
15 'rdbytes_kernel_to_login'. Additionally, some older versions of the
16 test produced keyval names such as 'sectors_read_kernel_to_login'.
17 These keyvals record an accumulated total measured from a fixed
18 time in the past (kernel startup), e.g. 'seconds_kernel_to_login'
19 records the total seconds from kernel startup to login screen
20 ready.
21
22 The boot time keyval names all start with the prefix
23 'seconds_kernel_to_', and record time in seconds since kernel
24 startup.
25
26 The disk read keyval names all start with the prefix
27 'rdbytes_kernel_to_', and record bytes read from the boot device
28 since kernel startup. The obsolete disk keyvals start with the
29 prefix 'sectors_read_kernel_to_' and record the same statistic
30 measured in 512-byte sectors.
31
32 Boot time and disk kevyal values have a consistent ordering
33 across iterations. For instance, if in one iteration the value of
34 'seconds_kernel_to_login' is greater than the value of
35 'seconds_kernel_to_x_started', then it will be greater in *all*
36 iterations. This property is a consequence of the underlying
37 measurement procedure; it is not enforced by this module.
38
39 """
40
41 import math
42
43
44 def _ListStats(list_):
45 # Utility function - calculate the average and (sample) standard
46 # deviation of a list of numbers. Result is float, even if the
47 # input list is full of int's
48 sum_ = 0.0
49 sumsq = 0.0
50 for v in list_:
51 sum_ += v
52 sumsq += v * v
53 n = len(list_)
54 avg = sum_ / n
55 var = (sumsq - sum_ * avg) / (n - 1)
56 if var < 0.0:
57 var = 0.0
58 dev = math.sqrt(var)
59 return (avg, dev)
60
61
62 def _DoCheck(dict_):
63 # Utility function - check the that all keyvals occur the same
64 # number of times. On success, return the number of occurrences;
65 # on failure return None
66 check = map(len, dict_.values())
67 if not check:
68 return None
69 for i in range(1, len(check)):
70 if check[i] != check[i-1]:
71 return None
72 return check[0]
73
74
75 def _KeyDelta(dict_, key0, key1):
76 # Utility function - return a list of the vector difference between
77 # two keyvals.
78 return map(lambda a, b: b - a, dict_[key0], dict_[key1])
79
80
81 class TestResultSet(object):
82 """A set of boot time and disk usage result statistics.
83
84 Objects of this class consist of two sets of result statistics:
85 the boot time statistics and the disk statistics.
86
87 Class TestResultsSet does not interpret or store keyval mappings
88 directly; iteration results are processed by attached _KeySet
89 objects, one for boot time (`_timekeys`), one for disk read
90 (`_diskkeys`). These attached _KeySet objects can be obtained
91 with appropriate methods; various methods on these objects will
92 calculate statistics on the results, and provide the raw data.
93
94 """
95
96 def __init__(self, name):
97 self.name = name
98 self._timekeys = _TimeKeySet()
99 self._diskkeys = _DiskKeySet()
100 self._olddiskkeys = _OldDiskKeySet()
101
102 def AddIterationResults(self, runkeys):
103 """Add keyval results from a single iteration.
104
105 A TestResultSet is constructed by repeatedly calling
106 AddRunResults(), iteration by iteration. Iteration results are
107 passed in as a dictionary mapping keyval attributes to values.
108 When all iteration results have been added, FinalizeResults()
109 makes the results available for analysis.
110
111 """
112
113 self._timekeys.AddRunResults(runkeys)
114 self._diskkeys.AddRunResults(runkeys)
115 self._olddiskkeys.AddRunResults(runkeys)
116
117 def FinalizeResults(self):
118 """Make results available for analysis.
119
120 A TestResultSet is constructed by repeatedly feeding it results,
121 iteration by iteration. Iteration results are passed in as a
122 dictionary mapping keyval attributes to values. When all iteration
123 results have been added, FinalizeResults() makes the results
124 available for analysis.
125
126 """
127
128 self._timekeys.FinalizeResults()
129 if not self._diskkeys.FinalizeResults():
130 self._olddiskkeys.FinalizeResults()
131 self._diskkeys = self._olddiskkeys
132 self._olddiskkeys = None
133
134 def TimeKeySet(self):
135 """Return the boot time statistics result set."""
136 return self._timekeys
137
138 def DiskKeySet(self):
139 """Return the disk read statistics result set."""
140 return self._diskkeys
141
142
143 class _KeySet(object):
144 """Container for a set of related statistics.
145
146 _KeySet is an abstract superclass for containing collections of
147 either boot time or disk read statistics. Statistics are stored
148 as a dictionary (`_keyvals`) mapping keyval names to lists of
149 values.
150
151 The mapped keyval names are shortened by stripping the prefix
152 that identifies the type of prefix (keyvals that don't start with
153 the proper prefix are ignored). So, for example, with boot time
154 keyvals, 'seconds_kernel_to_login' becomes 'login' (and
155 'rdbytes_kernel_to_login' is ignored).
156
157 A list of all valid keyval names is stored in the `markers`
158 instance variable. The list is sorted by the natural ordering of
159 the underlying values (see the module comments for more details).
160
161 The list of values associated with a given keyval name are indexed
162 in the order in which they were added. So, all values for a given
163 iteration are stored at the same index.
164
165 """
166
167 def __init__(self):
168 self._keyvals = {}
169
170 def AddRunResults(self, runkeys):
171 """Add results for one iteration."""
172
173 for key, value in runkeys.iteritems():
174 if not key.startswith(self.PREFIX):
175 continue
176 shortkey = key[len(self.PREFIX):]
177 keylist = self._keyvals.setdefault(shortkey, [])
178 keylist.append(self._ConvertVal(value))
179
180 def FinalizeResults(self):
181 """Finalize this object's results.
182
183 This method makes available the `markers` and `num_iterations`
184 instance variables. It also ensures that every keyval occurred
185 in every iteration by requiring that all keyvals have the same
186 number of data points.
187
188 """
189
190 count = _DoCheck(self._keyvals)
191 if count is None:
192 self.num_iterations = 0
193 self.markers = []
194 return False
195 self.num_iterations = count
196 keylist = map(lambda k: (self._keyvals[k][0], k),
197 self._keyvals.keys())
198 keylist.sort(key=lambda tp: tp[0])
199 self.markers = map(lambda tp: tp[1], keylist)
200 return True
201
202 def RawData(self, key):
203 """Return the list of values for the given marker key."""
204 return self._keyvals[key]
205
206 def DeltaData(self, key0, key1):
207 """Return vector difference of the values of the given keys."""
208 return _KeyDelta(self._keyvals, key0, key1)
209
210 def Statistics(self, key):
211 """Return the average and standard deviation of the key's values."""
212 return _ListStats(self._keyvals[key])
213
214 def DeltaStatistics(self, key0, key1):
215 """Return the average and standard deviation of the differences
216 between two keys.
217
218 """
219
220 return _ListStats(self.DeltaData(key0, key1))
221
222
223 class _TimeKeySet(_KeySet):
224 """Concrete subclass of _KeySet for boot time statistics."""
225
226 # TIME_KEY_PREFIX = 'seconds_kernel_to_'
227 PREFIX = 'seconds_kernel_to_'
228
229 # Time-based keyvals are reported in seconds and get converted to
230 # milliseconds
231 TIME_SCALE = 1000
232
233 def _ConvertVal(self, value):
234 # We use a "round to nearest int" formula here to make sure we
235 # don't lose anything in the conversion from decimal.
236 return int(self.TIME_SCALE * float(value) + 0.5)
237
238 def PrintableStatistic(self, value):
239 v = int(value + 0.5)
240 return ("%d" % v, v)
241
242
243 class _DiskKeySet(_KeySet):
244 """Concrete subclass of _KeySet for disk read statistics."""
245
246 PREFIX = 'rdbytes_kernel_to_'
247
248 # Disk read keyvals are reported in bytes and get converted to
249 # MBytes (1 MByte = 1 million bytes, not 2**20)
250 DISK_SCALE = 1.0e-6
251
252 def _ConvertVal(self, value):
253 return self.DISK_SCALE * float(value)
254
255 def PrintableStatistic(self, value):
256 v = round(value, 1)
257 return ("%.1fM" % v, v)
258
259
260 class _OldDiskKeySet(_DiskKeySet):
261 """Concrete subclass of _KeySet for the old-style disk read statistics."""
262
263 # Older versions of platform_BootPerf reported total sectors read
264 # using names of the form sectors_read_kernel_to_* (instead of the
265 # more recent rdbytes_kernel_to_*), but some of those names
266 # exceeded the 30-character limit in the MySQL database schema.
267 PREFIX = 'sectors_read_kernel_to_'
268
269 # Old sytle disk read keyvals are reported in 512-byte sectors and
270 # get converted to MBytes (1 MByte = 1 million bytes, not 2**20)
271 SECTOR_SCALE = 512 * _DiskKeySet.DISK_SCALE
272
273 def _ConvertVal(self, value):
274 return self.SECTOR_SCALE * float(value)
OLDNEW
« no previous file with comments | « bootperf-bin/perfprinter.py ('k') | bootperf-bin/showbootdata » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698