1# Copyright 2013 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 5import numbers 6 7from telemetry import value as value_module 8from telemetry.value import list_of_scalar_values 9from telemetry.value import none_values 10from telemetry.value import summarizable 11 12 13class ScalarValue(summarizable.SummarizableValue): 14 def __init__(self, page, name, units, value, important=True, 15 description=None, tir_label=None, 16 none_value_reason=None, improvement_direction=None, 17 grouping_keys=None): 18 """A single value (float or integer) result from a test. 19 20 A test that counts the number of DOM elements in a page might produce a 21 scalar value: 22 ScalarValue(page, 'num_dom_elements', 'count', num_elements) 23 """ 24 super(ScalarValue, self).__init__(page, name, units, important, description, 25 tir_label, improvement_direction, 26 grouping_keys) 27 assert value is None or isinstance(value, numbers.Number) 28 none_values.ValidateNoneValueReason(value, none_value_reason) 29 self.value = value 30 self.none_value_reason = none_value_reason 31 32 def __repr__(self): 33 if self.page: 34 page_name = self.page.display_name 35 else: 36 page_name = 'None' 37 return ('ScalarValue(%s, %s, %s, %s, important=%s, description=%s, ' 38 'tir_label=%s, improvement_direction=%s, grouping_keys=%s') % ( 39 page_name, 40 self.name, 41 self.units, 42 self.value, 43 self.important, 44 self.description, 45 self.tir_label, 46 self.improvement_direction, 47 self.grouping_keys) 48 49 def GetBuildbotDataType(self, output_context): 50 if self._IsImportantGivenOutputIntent(output_context): 51 return 'default' 52 return 'unimportant' 53 54 def GetBuildbotValue(self): 55 # Buildbot's print_perf_results method likes to get lists for all values, 56 # even when they are scalar, so list-ize the return value. 57 return [self.value] 58 59 def GetRepresentativeNumber(self): 60 return self.value 61 62 def GetRepresentativeString(self): 63 return str(self.value) 64 65 @staticmethod 66 def GetJSONTypeName(): 67 return 'scalar' 68 69 def AsDict(self): 70 d = super(ScalarValue, self).AsDict() 71 d['value'] = self.value 72 73 if self.none_value_reason is not None: 74 d['none_value_reason'] = self.none_value_reason 75 76 return d 77 78 @staticmethod 79 def FromDict(value_dict, page_dict): 80 kwargs = value_module.Value.GetConstructorKwArgs(value_dict, page_dict) 81 82 # Infinity and NaN are left out of JSON for security reasons that do not 83 # apply to our use cases, so TBMv2 serializes them as strings, 84 # but TBMv1 doesn't support them. 85 if value_dict['value'] in ['Infinity', '-Infinity', 'NaN']: 86 kwargs['value'] = None 87 kwargs['none_value_reason'] = 'value was ' + value_dict['value'] 88 else: 89 kwargs['value'] = value_dict['value'] 90 91 if 'improvement_direction' in value_dict: 92 kwargs['improvement_direction'] = value_dict['improvement_direction'] 93 if 'none_value_reason' in value_dict: 94 kwargs['none_value_reason'] = value_dict['none_value_reason'] 95 96 return ScalarValue(**kwargs) 97 98 @classmethod 99 def MergeLikeValuesFromSamePage(cls, values): 100 assert len(values) > 0 101 v0 = values[0] 102 return cls._MergeLikeValues(values, v0.page, v0.name, v0.grouping_keys) 103 104 @classmethod 105 def MergeLikeValuesFromDifferentPages(cls, values): 106 assert len(values) > 0 107 v0 = values[0] 108 return cls._MergeLikeValues(values, None, v0.name, v0.grouping_keys) 109 110 @classmethod 111 def _MergeLikeValues(cls, values, page, name, grouping_keys): 112 v0 = values[0] 113 114 merged_value = [v.value for v in values] 115 none_value_reason = None 116 if None in merged_value: 117 merged_value = None 118 merged_none_values = [v for v in values if v.value is None] 119 none_value_reason = ( 120 none_values.MERGE_FAILURE_REASON + 121 ' None values: %s' % repr(merged_none_values)) 122 return list_of_scalar_values.ListOfScalarValues( 123 page, name, v0.units, merged_value, important=v0.important, 124 description=v0.description, 125 tir_label=value_module.MergedTirLabel(values), 126 none_value_reason=none_value_reason, 127 improvement_direction=v0.improvement_direction, 128 grouping_keys=grouping_keys) 129