histogram.py revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 import value as value_module
7from telemetry import perf_tests_helper
8
9class HistogramValueBucket(object):
10  def __init__(self, low, high, count=0):
11    self.low = low
12    self.high = high
13    self.count = count
14
15  def ToJSONString(self):
16    return '{%s}' % ', '.join([
17      '"low": %i' % self.low,
18      '"high": %i' % self.high,
19      '"count": %i' % self.count])
20
21class HistogramValue(value_module.Value):
22  def __init__(self, page, name, units,
23               raw_value=None, raw_value_json=None, important=True):
24    super(HistogramValue, self).__init__(page, name, units, important)
25    if raw_value_json:
26      assert raw_value == None, 'Dont specify both raw_value and raw_value_json'
27      raw_value = json.loads(raw_value_json)
28    if raw_value:
29      assert 'buckets' in raw_value
30      assert isinstance(raw_value['buckets'], list)
31      self.buckets = []
32      for bucket in raw_value['buckets']:
33        self.buckets.append(HistogramValueBucket(
34          low=bucket['low'],
35          high=bucket['high'],
36          count=bucket['count']))
37    else:
38      self.buckets = []
39
40  def __repr__(self):
41    if self.page:
42      page_name = self.page.url
43    else:
44      page_name = None
45    return 'HistogramValue(%s, %s, %s, raw_json_string="%s", important=%s)' % (
46      page_name,
47      self.name, self.units,
48      self.ToJSONString(),
49      self.important)
50
51  def GetBuildbotDataType(self, output_context):
52    if self._IsImportantGivenOutputIntent(output_context):
53      return 'histogram'
54    return 'unimportant-histogram'
55
56  def GetBuildbotValue(self):
57    # More buildbot insanity: perf_tests_results_helper requires the histogram
58    # to be an array of size one.
59    return [self.ToJSONString()]
60
61  def ToJSONString(self):
62    # This has to hand-JSONify the histogram to ensure the order of keys
63    # produced is stable across different systems.
64    #
65    # This is done because the buildbot unittests are string equality
66    # assertions. Thus, tests that contain histograms require stable
67    # stringification of the histogram.
68    #
69    # Sigh, buildbot, Y U gotta be that way.
70    return '{"buckets": [%s]}' % (
71      ', '.join([b.ToJSONString() for b in self.buckets]))
72
73  def GetRepresentativeNumber(self):
74    (mean, _) = perf_tests_helper.GeomMeanAndStdDevFromHistogram(
75        self.ToJSONString())
76    return mean
77
78  def GetRepresentativeString(self):
79    return self.GetBuildbotValue()
80
81  @classmethod
82  def MergeLikeValuesFromSamePage(cls, values):
83    assert len(values) > 0
84    v0 = values[0]
85    return HistogramValue(
86        v0.page, v0.name, v0.units,
87        raw_value_json=v0.ToJSONString(),
88        important=v0.important)
89
90  @classmethod
91  def MergeLikeValuesFromDifferentPages(cls, values,
92                                        group_by_name_suffix=False):
93    # Histograms cannot be merged across pages, at least for now. It should be
94    # theoretically possible, just requires more work. Instead, return None.
95    # This signals to the merging code that the data is unmergable and it will
96    # cope accordingly.
97    return None
98