OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 The Value hierarchy provides a way of representing the values measurements | 5 The Value hierarchy provides a way of representing the values measurements |
6 produce such that they can be merged across runs, grouped by page, and output | 6 produce such that they can be merged across runs, grouped by page, and output |
7 to different targets. | 7 to different targets. |
8 | 8 |
9 The core Value concept provides the basic functionality: | 9 The core Value concept provides the basic functionality: |
10 - association with a page, may be none | 10 - association with a page, may be none |
(...skipping 24 matching lines...) Expand all Loading... |
35 # value is being interpreted actually affects the conversion. This is insane, | 35 # value is being interpreted actually affects the conversion. This is insane, |
36 # but there you have it. There are three contexts in which Values are converted | 36 # but there you have it. There are three contexts in which Values are converted |
37 # for use by buildbot, represented by these output-intent values. | 37 # for use by buildbot, represented by these output-intent values. |
38 PER_PAGE_RESULT_OUTPUT_CONTEXT = 'per-page-result-output-context' | 38 PER_PAGE_RESULT_OUTPUT_CONTEXT = 'per-page-result-output-context' |
39 COMPUTED_PER_PAGE_SUMMARY_OUTPUT_CONTEXT = 'merged-pages-result-output-context' | 39 COMPUTED_PER_PAGE_SUMMARY_OUTPUT_CONTEXT = 'merged-pages-result-output-context' |
40 SUMMARY_RESULT_OUTPUT_CONTEXT = 'summary-result-output-context' | 40 SUMMARY_RESULT_OUTPUT_CONTEXT = 'summary-result-output-context' |
41 | 41 |
42 class Value(object): | 42 class Value(object): |
43 """An abstract value produced by a telemetry page test. | 43 """An abstract value produced by a telemetry page test. |
44 """ | 44 """ |
45 def __init__(self, page, name, units, important, description): | 45 def __init__(self, page, name, units, important, description, |
| 46 interaction_record): |
46 """A generic Value object. | 47 """A generic Value object. |
47 | 48 |
48 Args: | 49 Args: |
49 page: A Page object, may be given as None to indicate that the value | 50 page: A Page object, may be given as None to indicate that the value |
50 represents results for multiple pages. | 51 represents results for multiple pages. |
51 name: A value name string, may contain a dot. Values from the same test | 52 name: A value name string, may contain a dot. Values from the same test |
52 with the same prefix before the dot may be considered to belong to | 53 with the same prefix before the dot may be considered to belong to |
53 the same chart. | 54 the same chart. |
54 units: A units string. | 55 units: A units string. |
55 important: Whether the value is "important". Causes the value to appear | 56 important: Whether the value is "important". Causes the value to appear |
56 by default in downstream UIs. | 57 by default in downstream UIs. |
57 description: A string explaining in human-understandable terms what this | 58 description: A string explaining in human-understandable terms what this |
58 value represents. | 59 value represents. |
| 60 interaction_record: The string label of the TimelineInteractionRecord with |
| 61 which this value is associated. |
59 """ | 62 """ |
60 # TODO(eakuefner): Check user story here after migration (crbug.com/442036) | 63 # TODO(eakuefner): Check user story here after migration (crbug.com/442036) |
61 if not isinstance(name, basestring): | 64 if not isinstance(name, basestring): |
62 raise ValueError('name field of Value must be string.') | 65 raise ValueError('name field of Value must be string.') |
63 if not isinstance(units, basestring): | 66 if not isinstance(units, basestring): |
64 raise ValueError('units field of Value must be string.') | 67 raise ValueError('units field of Value must be string.') |
65 if not isinstance(important, bool): | 68 if not isinstance(important, bool): |
66 raise ValueError('important field of Value must be bool.') | 69 raise ValueError('important field of Value must be bool.') |
67 if not ((description is None) or isinstance(description, basestring)): | 70 if not ((description is None) or isinstance(description, basestring)): |
68 raise ValueError('description field of Value must absent or string.') | 71 raise ValueError('description field of Value must absent or string.') |
| 72 if not ((interaction_record is None) or |
| 73 isinstance(interaction_record, basestring)): |
| 74 raise ValueError('interaction_record field of Value must absent or ' |
| 75 'string.') |
69 | 76 |
70 self.page = page | 77 self.page = page |
71 self.name = name | 78 self.name = name |
72 self.units = units | 79 self.units = units |
73 self.important = important | 80 self.important = important |
74 self.description = description | 81 self.description = description |
| 82 self.interaction_record = interaction_record |
75 | 83 |
76 def IsMergableWith(self, that): | 84 def IsMergableWith(self, that): |
77 return (self.units == that.units and | 85 return (self.units == that.units and |
78 type(self) == type(that) and | 86 type(self) == type(that) and |
79 self.important == that.important) | 87 self.important == that.important and |
| 88 self.interaction_record == that.interaction_record) |
80 | 89 |
81 @classmethod | 90 @classmethod |
82 def MergeLikeValuesFromSamePage(cls, values): | 91 def MergeLikeValuesFromSamePage(cls, values): |
83 """Combines the provided list of values into a single compound value. | 92 """Combines the provided list of values into a single compound value. |
84 | 93 |
85 When a page runs multiple times, it may produce multiple values. This | 94 When a page runs multiple times, it may produce multiple values. This |
86 function is given the same-named values across the multiple runs, and has | 95 function is given the same-named values across the multiple runs, and has |
87 the responsibility of producing a single result. | 96 the responsibility of producing a single result. |
88 | 97 |
89 It must return a single Value. If merging does not make sense, the | 98 It must return a single Value. If merging does not make sense, the |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 d = { | 198 d = { |
190 'name': self.name, | 199 'name': self.name, |
191 'type': self.GetJSONTypeName(), | 200 'type': self.GetJSONTypeName(), |
192 'units': self.units, | 201 'units': self.units, |
193 'important': self.important | 202 'important': self.important |
194 } | 203 } |
195 | 204 |
196 if self.description: | 205 if self.description: |
197 d['description'] = self.description | 206 d['description'] = self.description |
198 | 207 |
| 208 if self.interaction_record: |
| 209 d['interaction_record'] = self.interaction_record |
| 210 |
199 if self.page: | 211 if self.page: |
200 d['page_id'] = self.page.id | 212 d['page_id'] = self.page.id |
201 | 213 |
202 return d | 214 return d |
203 | 215 |
204 def AsDictWithoutBaseClassEntries(self): | 216 def AsDictWithoutBaseClassEntries(self): |
205 full_dict = self.AsDict() | 217 full_dict = self.AsDict() |
206 base_dict_keys = set(self._AsDictImpl().keys()) | 218 base_dict_keys = set(self._AsDictImpl().keys()) |
207 | 219 |
208 # Extracts only entries added by the subclass. | 220 # Extracts only entries added by the subclass. |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 d['description'] = None | 287 d['description'] = None |
276 | 288 |
277 page_id = value_dict.get('page_id', None) | 289 page_id = value_dict.get('page_id', None) |
278 if page_id: | 290 if page_id: |
279 d['page'] = page_dict[int(page_id)] | 291 d['page'] = page_dict[int(page_id)] |
280 else: | 292 else: |
281 d['page'] = None | 293 d['page'] = None |
282 | 294 |
283 d['important'] = False | 295 d['important'] = False |
284 | 296 |
| 297 interaction_record = value_dict.get('interaction_record', None) |
| 298 if interaction_record: |
| 299 d['interaction_record'] = interaction_record |
| 300 else: |
| 301 d['interaction_record'] = None |
| 302 |
285 return d | 303 return d |
286 | 304 |
287 def ValueNameFromTraceAndChartName(trace_name, chart_name=None): | 305 def ValueNameFromTraceAndChartName(trace_name, chart_name=None): |
288 """Mangles a trace name plus optional chart name into a standard string. | 306 """Mangles a trace name plus optional chart name into a standard string. |
289 | 307 |
290 A value might just be a bareword name, e.g. numPixels. In that case, its | 308 A value might just be a bareword name, e.g. numPixels. In that case, its |
291 chart may be None. | 309 chart may be None. |
292 | 310 |
293 But, a value might also be intended for display with other values, in which | 311 But, a value might also be intended for display with other values, in which |
294 case the chart name indicates that grouping. So, you might have | 312 case the chart name indicates that grouping. So, you might have |
(...skipping 14 matching lines...) Expand all Loading... |
309 whereas telemetry represents values with a chart_name.trace_name convention, | 327 whereas telemetry represents values with a chart_name.trace_name convention, |
310 where chart_name is optional. This convention is also used by chart_json. | 328 where chart_name is optional. This convention is also used by chart_json. |
311 | 329 |
312 This converts from the telemetry convention to the buildbot convention, | 330 This converts from the telemetry convention to the buildbot convention, |
313 returning a 2-tuple (measurement_name, trace_name). | 331 returning a 2-tuple (measurement_name, trace_name). |
314 """ | 332 """ |
315 if '.' in value_name: | 333 if '.' in value_name: |
316 return value_name.split('.', 1) | 334 return value_name.split('.', 1) |
317 else: | 335 else: |
318 return value_name, value_name | 336 return value_name, value_name |
OLD | NEW |