| 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 25 matching lines...) Expand all Loading... |
| 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 tir_label): | 46 tir_label, grouping_keys): |
| 47 """A generic Value object. | 47 """A generic Value object. |
| 48 | 48 |
| 49 Args: | 49 Args: |
| 50 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 |
| 51 represents results for multiple pages. | 51 represents results for multiple pages. |
| 52 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 |
| 53 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 |
| 54 the same chart. | 54 the same chart. |
| 55 units: A units string. | 55 units: A units string. |
| 56 important: Whether the value is "important". Causes the value to appear | 56 important: Whether the value is "important". Causes the value to appear |
| 57 by default in downstream UIs. | 57 by default in downstream UIs. |
| 58 description: A string explaining in human-understandable terms what this | 58 description: A string explaining in human-understandable terms what this |
| 59 value represents. | 59 value represents. |
| 60 tir_label: The string label of the TimelineInteractionRecord with | 60 tir_label: The string label of the TimelineInteractionRecord with |
| 61 which this value is associated. | 61 which this value is associated. |
| 62 grouping_keys: A dict that maps grouping key names to grouping keys. |
| 62 """ | 63 """ |
| 63 # TODO(eakuefner): Check story here after migration (crbug.com/442036) | 64 # TODO(eakuefner): Check story here after migration (crbug.com/442036) |
| 64 if not isinstance(name, basestring): | 65 if not isinstance(name, basestring): |
| 65 raise ValueError('name field of Value must be string.') | 66 raise ValueError('name field of Value must be string.') |
| 66 if not isinstance(units, basestring): | 67 if not isinstance(units, basestring): |
| 67 raise ValueError('units field of Value must be string.') | 68 raise ValueError('units field of Value must be string.') |
| 68 if not isinstance(important, bool): | 69 if not isinstance(important, bool): |
| 69 raise ValueError('important field of Value must be bool.') | 70 raise ValueError('important field of Value must be bool.') |
| 70 if not ((description is None) or isinstance(description, basestring)): | 71 if not ((description is None) or isinstance(description, basestring)): |
| 71 raise ValueError('description field of Value must absent or string.') | 72 raise ValueError('description field of Value must absent or string.') |
| 72 if not ((tir_label is None) or | 73 if not ((tir_label is None) or |
| 73 isinstance(tir_label, basestring)): | 74 isinstance(tir_label, basestring)): |
| 74 raise ValueError('tir_label field of Value must absent or ' | 75 raise ValueError('tir_label field of Value must absent or ' |
| 75 'string.') | 76 'string.') |
| 77 if not ((grouping_keys is None) or isinstance(grouping_keys, dict)): |
| 78 raise ValueError('grouping_keys field of Value must be absent or dict') |
| 79 |
| 80 if grouping_keys is None: |
| 81 grouping_keys = {} |
| 76 | 82 |
| 77 self.page = page | 83 self.page = page |
| 78 self.name = name | 84 self.name = name |
| 79 self.units = units | 85 self.units = units |
| 80 self.important = important | 86 self.important = important |
| 81 self.description = description | 87 self.description = description |
| 82 self.tir_label = tir_label | 88 self.tir_label = tir_label |
| 89 self.grouping_keys = grouping_keys |
| 83 | 90 |
| 84 def __eq__(self, other): | 91 def __eq__(self, other): |
| 85 return hash(self) == hash(other) | 92 return hash(self) == hash(other) |
| 86 | 93 |
| 87 def __hash__(self): | 94 def __hash__(self): |
| 88 return hash(str(self)) | 95 return hash(str(self)) |
| 89 | 96 |
| 90 def IsMergableWith(self, that): | 97 def IsMergableWith(self, that): |
| 91 return (self.units == that.units and | 98 return (self.units == that.units and |
| 92 type(self) == type(that) and | 99 type(self) == type(that) and |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 | 211 |
| 205 if self.description: | 212 if self.description: |
| 206 d['description'] = self.description | 213 d['description'] = self.description |
| 207 | 214 |
| 208 if self.tir_label: | 215 if self.tir_label: |
| 209 d['tir_label'] = self.tir_label | 216 d['tir_label'] = self.tir_label |
| 210 | 217 |
| 211 if self.page: | 218 if self.page: |
| 212 d['page_id'] = self.page.id | 219 d['page_id'] = self.page.id |
| 213 | 220 |
| 221 if self.grouping_keys: |
| 222 d['grouping_keys'] = self.grouping_keys |
| 223 |
| 214 return d | 224 return d |
| 215 | 225 |
| 216 def AsDictWithoutBaseClassEntries(self): | 226 def AsDictWithoutBaseClassEntries(self): |
| 217 full_dict = self.AsDict() | 227 full_dict = self.AsDict() |
| 218 base_dict_keys = set(self._AsDictImpl().keys()) | 228 base_dict_keys = set(self._AsDictImpl().keys()) |
| 219 | 229 |
| 220 # Extracts only entries added by the subclass. | 230 # Extracts only entries added by the subclass. |
| 221 return dict([(k, v) for (k, v) in full_dict.iteritems() | 231 return dict([(k, v) for (k, v) in full_dict.iteritems() |
| 222 if k not in base_dict_keys]) | 232 if k not in base_dict_keys]) |
| 223 | 233 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 d['page'] = None | 303 d['page'] = None |
| 294 | 304 |
| 295 d['important'] = False | 305 d['important'] = False |
| 296 | 306 |
| 297 tir_label = value_dict.get('tir_label', None) | 307 tir_label = value_dict.get('tir_label', None) |
| 298 if tir_label: | 308 if tir_label: |
| 299 d['tir_label'] = tir_label | 309 d['tir_label'] = tir_label |
| 300 else: | 310 else: |
| 301 d['tir_label'] = None | 311 d['tir_label'] = None |
| 302 | 312 |
| 313 grouping_keys = value_dict.get('grouping_keys', None) |
| 314 if grouping_keys: |
| 315 d['grouping_keys'] = grouping_keys |
| 316 else: |
| 317 d['grouping_keys'] = None |
| 318 |
| 303 return d | 319 return d |
| 304 | 320 |
| 305 def ValueNameFromTraceAndChartName(trace_name, chart_name=None): | 321 def ValueNameFromTraceAndChartName(trace_name, chart_name=None): |
| 306 """Mangles a trace name plus optional chart name into a standard string. | 322 """Mangles a trace name plus optional chart name into a standard string. |
| 307 | 323 |
| 308 A value might just be a bareword name, e.g. numPixels. In that case, its | 324 A value might just be a bareword name, e.g. numPixels. In that case, its |
| 309 chart may be None. | 325 chart may be None. |
| 310 | 326 |
| 311 But, a value might also be intended for display with other values, in which | 327 But, a value might also be intended for display with other values, in which |
| 312 case the chart name indicates that grouping. So, you might have | 328 case the chart name indicates that grouping. So, you might have |
| (...skipping 14 matching lines...) Expand all Loading... |
| 327 whereas telemetry represents values with a chart_name.trace_name convention, | 343 whereas telemetry represents values with a chart_name.trace_name convention, |
| 328 where chart_name is optional. This convention is also used by chart_json. | 344 where chart_name is optional. This convention is also used by chart_json. |
| 329 | 345 |
| 330 This converts from the telemetry convention to the buildbot convention, | 346 This converts from the telemetry convention to the buildbot convention, |
| 331 returning a 2-tuple (measurement_name, trace_name). | 347 returning a 2-tuple (measurement_name, trace_name). |
| 332 """ | 348 """ |
| 333 if '.' in value_name: | 349 if '.' in value_name: |
| 334 return value_name.split('.', 1) | 350 return value_name.split('.', 1) |
| 335 else: | 351 else: |
| 336 return value_name, value_name | 352 return value_name, value_name |
| OLD | NEW |