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. 4import json 5 6from telemetry.util import perf_tests_helper 7from telemetry import value as value_module 8from telemetry.value import histogram_util 9from telemetry.value import summarizable 10 11 12class HistogramValueBucket(object): 13 def __init__(self, low, high, count=0): 14 self.low = low 15 self.high = high 16 self.count = count 17 18 def AsDict(self): 19 return { 20 'low': self.low, 21 'high': self.high, 22 'count': self.count 23 } 24 25 def ToJSONString(self): 26 return '{%s}' % ', '.join([ 27 '"low": %i' % self.low, 28 '"high": %i' % self.high, 29 '"count": %i' % self.count]) 30 31class HistogramValue(summarizable.SummarizableValue): 32 def __init__(self, page, name, units, 33 raw_value=None, raw_value_json=None, important=True, 34 description=None, tir_label=None, improvement_direction=None, 35 grouping_keys=None): 36 super(HistogramValue, self).__init__(page, name, units, important, 37 description, tir_label, 38 improvement_direction, grouping_keys) 39 if raw_value_json: 40 assert raw_value == None, \ 41 'Don\'t specify both raw_value and raw_value_json' 42 raw_value = json.loads(raw_value_json) 43 if raw_value: 44 self.buckets = [] 45 for bucket in histogram_util.GetHistogramBucketsFromRawValue(raw_value): 46 self.buckets.append(HistogramValueBucket( 47 low=bucket['low'], 48 high=bucket['high'], 49 count=bucket['count'])) 50 else: 51 self.buckets = [] 52 53 def __repr__(self): 54 if self.page: 55 page_name = self.page.display_name 56 else: 57 page_name = 'None' 58 return ('HistogramValue(%s, %s, %s, raw_json_string=%s, ' 59 'important=%s, description=%s, tir_label=%s, ' 60 'improvement_direction=%s, grouping_keys=%s)') % ( 61 page_name, 62 self.name, self.units, 63 self.ToJSONString(), 64 self.important, 65 self.description, 66 self.tir_label, 67 self.improvement_direction, 68 self.grouping_keys) 69 70 def GetBuildbotDataType(self, output_context): 71 if self._IsImportantGivenOutputIntent(output_context): 72 return 'histogram' 73 return 'unimportant-histogram' 74 75 def GetBuildbotValue(self): 76 # More buildbot insanity: perf_tests_results_helper requires the histogram 77 # to be an array of size one. 78 return [self.ToJSONString()] 79 80 def ToJSONString(self): 81 # This has to hand-JSONify the histogram to ensure the order of keys 82 # produced is stable across different systems. 83 # 84 # This is done because the buildbot unittests are string equality 85 # assertions. Thus, tests that contain histograms require stable 86 # stringification of the histogram. 87 # 88 # Sigh, buildbot, Y U gotta be that way. 89 return '{"buckets": [%s]}' % ( 90 ', '.join([b.ToJSONString() for b in self.buckets])) 91 92 def GetRepresentativeNumber(self): 93 (mean, _) = perf_tests_helper.GeomMeanAndStdDevFromHistogram( 94 self.ToJSONString()) 95 return mean 96 97 def GetRepresentativeString(self): 98 return self.GetBuildbotValue() 99 100 @staticmethod 101 def GetJSONTypeName(): 102 return 'histogram' 103 104 def AsDict(self): 105 d = super(HistogramValue, self).AsDict() 106 d['buckets'] = [b.AsDict() for b in self.buckets] 107 return d 108 109 @staticmethod 110 def FromDict(value_dict, page_dict): 111 kwargs = value_module.Value.GetConstructorKwArgs(value_dict, page_dict) 112 kwargs['raw_value'] = value_dict 113 114 if 'improvement_direction' in value_dict: 115 kwargs['improvement_direction'] = value_dict['improvement_direction'] 116 117 return HistogramValue(**kwargs) 118 119 @classmethod 120 def MergeLikeValuesFromSamePage(cls, values): 121 assert len(values) > 0 122 v0 = values[0] 123 return HistogramValue( 124 v0.page, v0.name, v0.units, 125 raw_value_json=histogram_util.AddHistograms( 126 [v.ToJSONString() for v in values]), 127 description=v0.description, 128 important=v0.important, tir_label=v0.tir_label, 129 improvement_direction=v0.improvement_direction, 130 grouping_keys=v0.grouping_keys) 131 132 @classmethod 133 def MergeLikeValuesFromDifferentPages(cls, values): 134 # Histograms cannot be merged across pages, at least for now. It should be 135 # theoretically possible, just requires more work. Instead, return None. 136 # This signals to the merging code that the data is unmergable and it will 137 # cope accordingly. 138 return None 139