blob: 4b1f2ca102b50610aef7ddf2eef3d0e21b16c17c [file] [edit]
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import copy
import json
import math
from multiprocessing.dummy import Pool as ThreadPool
import unittest
from six.moves import range # pylint: disable=redefined-builtin
from tracing.value import histogram
from tracing.value.diagnostics import date_range
from tracing.value.diagnostics import diagnostic
from tracing.value.diagnostics import diagnostic_ref
from tracing.value.diagnostics import generic_set
from tracing.value.diagnostics import related_event_set
from tracing.value.diagnostics import related_name_map
from tracing.value.diagnostics import reserved_infos
from tracing.value.diagnostics import unmergeable_diagnostic_set as ums
# pylint: disable=too-many-lines
class PercentToStringUnittest(unittest.TestCase):
def testPercentToString(self):
with self.assertRaises(Exception) as ex:
histogram.PercentToString(-1)
self.assertEqual(str(ex.exception), 'percent must be in [0,1]')
with self.assertRaises(Exception) as ex:
histogram.PercentToString(2)
self.assertEqual(str(ex.exception), 'percent must be in [0,1]')
self.assertEqual(histogram.PercentToString(0), '000')
self.assertEqual(histogram.PercentToString(1), '100')
with self.assertRaises(Exception) as ex:
histogram.PercentToString(float('nan'))
self.assertEqual(str(ex.exception), 'Unexpected percent')
self.assertEqual(histogram.PercentToString(0.50), '050')
self.assertEqual(histogram.PercentToString(0.95), '095')
class StatisticsUnittest(unittest.TestCase):
def testFindHighIndexInSortedArray(self):
self.assertEqual(histogram.FindHighIndexInSortedArray(
list(range(0, -10, -1)), lambda x: x + 5), 6)
def testUniformlySampleArray(self):
self.assertEqual(len(histogram.UniformlySampleArray(
list(range(10)), 5)), 5)
def testUniformlySampleStream(self):
samples = []
histogram.UniformlySampleStream(samples, 1, 'A', 5)
self.assertEqual(samples, ['A'])
histogram.UniformlySampleStream(samples, 2, 'B', 5)
histogram.UniformlySampleStream(samples, 3, 'C', 5)
histogram.UniformlySampleStream(samples, 4, 'D', 5)
histogram.UniformlySampleStream(samples, 5, 'E', 5)
self.assertEqual(samples, ['A', 'B', 'C', 'D', 'E'])
histogram.UniformlySampleStream(samples, 6, 'F', 5)
self.assertEqual(len(samples), 5)
samples = [0, 0, 0]
histogram.UniformlySampleStream(samples, 1, 'G', 5)
self.assertEqual(samples, ['G', 0, 0])
def testMergeSampledStreams(self):
samples = []
histogram.MergeSampledStreams(samples, 0, ['A'], 1, 5)
self.assertEqual(samples, ['A'])
histogram.MergeSampledStreams(samples, 1, ['B', 'C', 'D', 'E'], 4, 5)
self.assertEqual(samples, ['A', 'B', 'C', 'D', 'E'])
histogram.MergeSampledStreams(samples, 9, ['F', 'G', 'H', 'I', 'J'], 7, 5)
self.assertEqual(len(samples), 5)
class RangeUnittest(unittest.TestCase):
def testAddValue(self):
r = histogram.Range()
self.assertEqual(r.empty, True)
r.AddValue(1)
self.assertEqual(r.empty, False)
self.assertEqual(r.min, 1)
self.assertEqual(r.max, 1)
self.assertEqual(r.center, 1)
r.AddValue(2)
self.assertEqual(r.empty, False)
self.assertEqual(r.min, 1)
self.assertEqual(r.max, 2)
self.assertEqual(r.center, 1.5)
class RunningStatisticsUnittest(unittest.TestCase):
def _Run(self, data):
running = histogram.RunningStatistics()
for datum in data:
running.Add(datum)
return running
def testStatistics(self):
running = self._Run([1, 2, 3])
self.assertEqual(running.sum, 6)
self.assertEqual(running.mean, 2)
self.assertEqual(running.min, 1)
self.assertEqual(running.max, 3)
self.assertEqual(running.variance, 1)
self.assertEqual(running.stddev, 1)
self.assertEqual(running.geometric_mean, math.pow(6, 1./3))
self.assertEqual(running.count, 3)
running = self._Run([2, 4, 4, 2])
self.assertEqual(running.sum, 12)
self.assertEqual(running.mean, 3)
self.assertEqual(running.min, 2)
self.assertEqual(running.max, 4)
self.assertEqual(running.variance, 4./3)
self.assertEqual(running.stddev, math.sqrt(4./3))
self.assertAlmostEqual(running.geometric_mean, math.pow(64, 1./4))
self.assertEqual(running.count, 4)
def testMerge(self):
def Compare(data1, data2):
a_running = self._Run(data1 + data2)
b_running = self._Run(data1).Merge(self._Run(data2))
CompareRunningStatistics(a_running, b_running)
a_running = histogram.RunningStatistics.FromDict(a_running.AsDict())
CompareRunningStatistics(a_running, b_running)
b_running = histogram.RunningStatistics.FromDict(b_running.AsDict())
CompareRunningStatistics(a_running, b_running)
def CompareRunningStatistics(a_running, b_running):
self.assertEqual(a_running.sum, b_running.sum)
self.assertEqual(a_running.mean, b_running.mean)
self.assertEqual(a_running.min, b_running.min)
self.assertEqual(a_running.max, b_running.max)
self.assertAlmostEqual(a_running.variance, b_running.variance)
self.assertAlmostEqual(a_running.stddev, b_running.stddev)
self.assertAlmostEqual(a_running.geometric_mean, b_running.geometric_mean)
self.assertEqual(a_running.count, b_running.count)
Compare([], [])
Compare([], [1, 2, 3])
Compare([1, 2, 3], [])
Compare([1, 2, 3], [10, 20, 100])
Compare([1, 1, 1, 1, 1], [10, 20, 10, 40])
def ToJSON(x):
return json.dumps(x, separators=(',', ':'), sort_keys=True)
class HistogramUnittest(unittest.TestCase):
TEST_BOUNDARIES = histogram.HistogramBinBoundaries.CreateLinear(0, 1000, 10)
def assertDeepEqual(self, a, b):
self.assertEqual(ToJSON(a), ToJSON(b))
def testDefaultBoundaries(self):
hist = histogram.Histogram('', 'ms')
self.assertEqual(len(hist.bins), 102)
hist = histogram.Histogram('', 'tsMs')
self.assertEqual(len(hist.bins), 1002)
hist = histogram.Histogram('', 'n%')
self.assertEqual(len(hist.bins), 22)
hist = histogram.Histogram('', 'n%+')
self.assertEqual(len(hist.bins), 22)
hist = histogram.Histogram('', 'n%-')
self.assertEqual(len(hist.bins), 22)
hist = histogram.Histogram('', 'sizeInBytes')
self.assertEqual(len(hist.bins), 102)
hist = histogram.Histogram('', 'J')
self.assertEqual(len(hist.bins), 52)
hist = histogram.Histogram('', 'W')
self.assertEqual(len(hist.bins), 52)
hist = histogram.Histogram('', 'unitless')
self.assertEqual(len(hist.bins), 52)
hist = histogram.Histogram('', 'count')
self.assertEqual(len(hist.bins), 22)
hist = histogram.Histogram('', 'sigma')
self.assertEqual(len(hist.bins), 52)
hist = histogram.Histogram('', 'sigma_smallerIsBetter')
self.assertEqual(len(hist.bins), 52)
hist = histogram.Histogram('', 'sigma_biggerIsBetter')
self.assertEqual(len(hist.bins), 52)
def testSerializationSize(self):
hist = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
d = hist.AsDict()
self.assertEqual(61, len(ToJSON(d)))
self.assertIsNone(d.get('allBins'))
self.assertDeepEqual(d, histogram.Histogram.FromDict(d).AsDict())
hist.AddSample(100)
d = hist.AsDict()
self.assertEqual(152, len(ToJSON(d)))
self.assertIsInstance(d['allBins'], dict)
self.assertDeepEqual(d, histogram.Histogram.FromDict(d).AsDict())
hist.AddSample(100)
d = hist.AsDict()
# SAMPLE_VALUES grew by "100,"
self.assertEqual(156, len(ToJSON(d)))
self.assertIsInstance(d['allBins'], dict)
self.assertDeepEqual(d, histogram.Histogram.FromDict(d).AsDict())
hist.AddSample(271, {'foo': generic_set.GenericSet(['bar'])})
d = hist.AsDict()
self.assertEqual(222, len(ToJSON(d)))
self.assertIsInstance(d['allBins'], dict)
self.assertDeepEqual(d, histogram.Histogram.FromDict(d).AsDict())
# Add samples to most bins so that allBinsArray is more efficient than
# allBinsDict.
for i in range(10, 100):
hist.AddSample(10 * i)
d = hist.AsDict()
self.assertEqual(651, len(ToJSON(d)))
self.assertIsInstance(d['allBins'], list)
self.assertDeepEqual(d, histogram.Histogram.FromDict(d).AsDict())
# Lowering maxNumSampleValues takes a random sub-sample of the existing
# sampleValues. We have deliberately set all samples to 3-digit numbers so
# that the serialized size is constant regardless of which samples are
# retained.
hist.max_num_sample_values = 10
d = hist.AsDict()
self.assertEqual(343, len(ToJSON(d)))
self.assertIsInstance(d['allBins'], list)
self.assertDeepEqual(d, histogram.Histogram.FromDict(d).AsDict())
# Test the case where 'allBins' isn't a list and we're attempting to index
# an invalid bucket.
e = copy.deepcopy(d)
e['allBins'] = {'1000': {}}
with self.assertRaises(histogram.InvalidBucketError):
_ = histogram.Histogram.FromDict(e).AsDict()
def testManyBinsRoundtrip(self):
# In this test we want to create a histogram which will have less than half
# of the bins populated, so we can force the bin compaction (instead of a
# list of bins, use a dictionary of bins) to do the conversion. We ensure
# that the dict key ordering is not going to be an issue in the
# serialisation and deserialisation roundtrip.
hist = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
# 400 allows us to fit the elements in approximately log10(10000) bins which
# should give us more empty bins than there are non-empty bins. We also add
# samples from either end of the range, by treating odd numbers in the
# beginning and even numbers as negative offsets from the max of the range
# (10,000).
for sample in range(0, 400):
hist.AddSample(sample if sample % 2 else 10000 - sample)
d = hist.AsDict()
self.assertIsInstance(d['allBins'], dict)
self.assertEqual(400, hist.num_values)
self.assertEqual((len(hist.bins) / 2) - 1, len(d['allBins']))
# Ensure that we can reconstitute a histogram properly from a dict.
e = histogram.Histogram.FromDict(d)
self.assertEqual(d, e.AsDict())
def testManyBinsRoundtripProto(self):
hist = histogram.Histogram('name', 'unitless', self.TEST_BOUNDARIES)
for sample in range(0, 400):
hist.AddSample(sample if sample % 2 else 10000 - sample)
d = hist.AsProto()
self.assertEqual(400, hist.num_values)
self.assertEqual((len(hist.bins) / 2) - 1, len(d.all_bins))
# Ensure that we can reconstitute a histogram properly from a proto.
e = histogram.Histogram.FromProto(d)
self.assertEqual(d, e.AsProto())
def testBasic(self):
hist = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
self.assertEqual(hist.GetBinForValue(250).range.min, 200)
self.assertEqual(hist.GetBinForValue(250).range.max, 300)
hist.AddSample(-1)
hist.AddSample(0)
hist.AddSample(0)
hist.AddSample(500)
hist.AddSample(999)
hist.AddSample(1000)
self.assertEqual(hist.bins[0].count, 1)
self.assertEqual(hist.GetBinForValue(0).count, 2)
self.assertEqual(hist.GetBinForValue(500).count, 1)
self.assertEqual(hist.GetBinForValue(999).count, 1)
self.assertEqual(hist.bins[-1].count, 1)
self.assertEqual(hist.num_values, 6)
self.assertAlmostEqual(hist.average, 416.3333333)
def testNans(self):
hist = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
hist.AddSample(None)
hist.AddSample(float('nan'))
self.assertEqual(hist.num_nans, 2)
def testAddHistogramValid(self):
hist0 = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
hist1 = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
hist0.AddSample(0)
hist0.AddSample(None)
hist1.AddSample(1)
hist1.AddSample(float('nan'))
hist0.AddHistogram(hist1)
self.assertEqual(hist0.num_nans, 2)
self.assertEqual(hist0.GetBinForValue(0).count, 2)
def testAddHistogramInvalid(self):
hist0 = histogram.Histogram(
'', 'ms', histogram.HistogramBinBoundaries.CreateLinear(0, 1000, 10))
hist1 = histogram.Histogram(
'', 'unitless', histogram.HistogramBinBoundaries.CreateLinear(
0, 1000, 10))
hist2 = histogram.Histogram(
'', 'ms', histogram.HistogramBinBoundaries.CreateLinear(0, 1001, 10))
hist3 = histogram.Histogram(
'', 'ms', histogram.HistogramBinBoundaries.CreateLinear(0, 1000, 11))
hists = [hist0, hist1, hist2, hist3]
for hista in hists:
for histb in hists:
if hista is histb:
continue
self.assertFalse(hista.CanAddHistogram(histb))
with self.assertRaises(Exception):
hista.AddHistogram(histb)
def testPercentile(self):
def Check(ary, mn, mx, bins, precision):
boundaries = histogram.HistogramBinBoundaries.CreateLinear(mn, mx, bins)
hist = histogram.Histogram('', 'ms', boundaries)
for x in ary:
hist.AddSample(x)
for percent in [0.25, 0.5, 0.75, 0.8, 0.95, 0.99]:
self.assertLessEqual(
abs(histogram.Percentile(ary, percent) -
hist.GetApproximatePercentile(percent)), precision)
Check([1, 2, 5, 7], 0.5, 10.5, 10, 1e-3)
Check([3, 3, 4, 4], 0.5, 10.5, 10, 1e-3)
Check([1, 10], 0.5, 10.5, 10, 1e-3)
Check([1, 2, 3, 4, 5], 0.5, 10.5, 10, 1e-3)
Check([3, 3, 3, 3, 3], 0.5, 10.5, 10, 1e-3)
Check([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0.5, 10.5, 10, 1e-3)
Check([1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10], 0.5, 10.5, 10, 1e-3)
Check([0, 11], 0.5, 10.5, 10, 1)
Check([0, 6, 11], 0.5, 10.5, 10, 1)
array = []
for i in range(1000):
array.append((i * i) % 10 + 1)
Check(array, 0.5, 10.5, 10, 1e-3)
# If the real percentile is outside the bin range then the approximation
# error can be high.
Check([-10000], 0, 10, 10, 10000)
Check([10000], 0, 10, 10, 10000 - 10)
# The result is no more than the bin width away from the real percentile.
Check([1, 1], 0, 10, 1, 10)
def _CheckBoundaries(self, boundaries, expected_min_boundary,
expected_max_boundary, expected_bin_ranges):
self.assertEqual(boundaries.range.min, expected_min_boundary)
self.assertEqual(boundaries.range.max, expected_max_boundary)
# Check that the boundaries can be used multiple times.
for _ in range(3):
hist = histogram.Histogram('', 'unitless', boundaries)
self.assertEqual(len(expected_bin_ranges), len(hist.bins))
for j, hbin in enumerate(hist.bins):
self.assertAlmostEqual(hbin.range.min, expected_bin_ranges[j].min)
self.assertAlmostEqual(hbin.range.max, expected_bin_ranges[j].max)
def testAddBinBoundary(self):
b = histogram.HistogramBinBoundaries(-100)
b.AddBinBoundary(50)
self._CheckBoundaries(b, -100, 50, [
histogram.Range.FromExplicitRange(-histogram.JS_MAX_VALUE, -100),
histogram.Range.FromExplicitRange(-100, 50),
histogram.Range.FromExplicitRange(50, histogram.JS_MAX_VALUE),
])
b.AddBinBoundary(60)
b.AddBinBoundary(75)
self._CheckBoundaries(b, -100, 75, [
histogram.Range.FromExplicitRange(-histogram.JS_MAX_VALUE, -100),
histogram.Range.FromExplicitRange(-100, 50),
histogram.Range.FromExplicitRange(50, 60),
histogram.Range.FromExplicitRange(60, 75),
histogram.Range.FromExplicitRange(75, histogram.JS_MAX_VALUE),
])
def testAddLinearBins(self):
b = histogram.HistogramBinBoundaries(1000)
b.AddLinearBins(1200, 5)
self._CheckBoundaries(b, 1000, 1200, [
histogram.Range.FromExplicitRange(-histogram.JS_MAX_VALUE, 1000),
histogram.Range.FromExplicitRange(1000, 1040),
histogram.Range.FromExplicitRange(1040, 1080),
histogram.Range.FromExplicitRange(1080, 1120),
histogram.Range.FromExplicitRange(1120, 1160),
histogram.Range.FromExplicitRange(1160, 1200),
histogram.Range.FromExplicitRange(1200, histogram.JS_MAX_VALUE),
])
def testAddExponentialBins(self):
b = histogram.HistogramBinBoundaries(0.5)
b.AddExponentialBins(8, 4)
self._CheckBoundaries(b, 0.5, 8, [
histogram.Range.FromExplicitRange(-histogram.JS_MAX_VALUE, 0.5),
histogram.Range.FromExplicitRange(0.5, 1),
histogram.Range.FromExplicitRange(1, 2),
histogram.Range.FromExplicitRange(2, 4),
histogram.Range.FromExplicitRange(4, 8),
histogram.Range.FromExplicitRange(8, histogram.JS_MAX_VALUE),
])
def testBinBoundariesCombined(self):
b = histogram.HistogramBinBoundaries(-273.15)
b.AddBinBoundary(-50)
b.AddLinearBins(4, 3)
b.AddExponentialBins(16, 2)
b.AddLinearBins(17, 4)
b.AddBinBoundary(100)
self._CheckBoundaries(b, -273.15, 100, [
histogram.Range.FromExplicitRange(-histogram.JS_MAX_VALUE, -273.15),
histogram.Range.FromExplicitRange(-273.15, -50),
histogram.Range.FromExplicitRange(-50, -32),
histogram.Range.FromExplicitRange(-32, -14),
histogram.Range.FromExplicitRange(-14, 4),
histogram.Range.FromExplicitRange(4, 8),
histogram.Range.FromExplicitRange(8, 16),
histogram.Range.FromExplicitRange(16, 16.25),
histogram.Range.FromExplicitRange(16.25, 16.5),
histogram.Range.FromExplicitRange(16.5, 16.75),
histogram.Range.FromExplicitRange(16.75, 17),
histogram.Range.FromExplicitRange(17, 100),
histogram.Range.FromExplicitRange(100, histogram.JS_MAX_VALUE)
])
def testBinBoundariesRaises(self):
b = histogram.HistogramBinBoundaries(-7)
with self.assertRaises(Exception):
b.AddBinBoundary(-10)
with self.assertRaises(Exception):
b.AddBinBoundary(-7)
with self.assertRaises(Exception):
b.AddLinearBins(-10, 10)
with self.assertRaises(Exception):
b.AddLinearBins(-7, 10)
with self.assertRaises(Exception):
b.AddLinearBins(10, 0)
with self.assertRaises(Exception):
b.AddExponentialBins(16, 4)
b = histogram.HistogramBinBoundaries(8)
with self.assertRaises(Exception):
b.AddExponentialBins(20, 0)
with self.assertRaises(Exception):
b.AddExponentialBins(5, 3)
with self.assertRaises(Exception):
b.AddExponentialBins(8, 3)
def testStatisticsScalars(self):
b = histogram.HistogramBinBoundaries.CreateLinear(0, 100, 100)
hist = histogram.Histogram('', 'unitless', b)
hist.AddSample(50)
hist.AddSample(60)
hist.AddSample(70)
hist.AddSample('i am not a number')
hist.CustomizeSummaryOptions({
'count': True,
'min': True,
'max': True,
'sum': True,
'avg': True,
'std': True,
'nans': True,
'geometricMean': True,
'percentile': [0.5, 1],
'ci': [0.01, 0.95],
})
# Test round-tripping summaryOptions
hist = hist.Clone()
stats = hist.statistics_scalars
self.assertEqual(stats['nans'].unit, 'count_smallerIsBetter')
self.assertEqual(stats['nans'].value, 1)
self.assertEqual(stats['count'].unit, 'count_smallerIsBetter')
self.assertEqual(stats['count'].value, 3)
self.assertEqual(stats['min'].unit, hist.unit)
self.assertEqual(stats['min'].value, 50)
self.assertEqual(stats['max'].unit, hist.unit)
self.assertEqual(stats['max'].value, 70)
self.assertEqual(stats['sum'].unit, hist.unit)
self.assertEqual(stats['sum'].value, 180)
self.assertEqual(stats['avg'].unit, hist.unit)
self.assertEqual(stats['avg'].value, 60)
self.assertEqual(stats['std'].unit, hist.unit)
self.assertEqual(stats['std'].value, 10)
self.assertEqual(stats['pct_050'].unit, hist.unit)
self.assertEqual(stats['pct_050'].value, 60.5)
self.assertEqual(stats['pct_100'].unit, hist.unit)
self.assertEqual(stats['pct_100'].value, 70.5)
self.assertEqual(stats['geometricMean'].unit, hist.unit)
self.assertLess(abs(stats['geometricMean'].value - 59.439), 1e-3)
self.assertLess(stats['ci_095_lower'].value, stats['avg'].value)
self.assertLess(stats['avg'].value, stats['ci_095_upper'].value)
self.assertEqual(stats['ci_001_lower'].value, stats['avg'].value)
self.assertEqual(stats['ci_001_upper'].value, stats['avg'].value)
hist.CustomizeSummaryOptions({
'count': False,
'min': False,
'max': False,
'sum': False,
'avg': False,
'std': False,
'nans': False,
'geometricMean': False,
'percentile': [],
'ci': [],
})
self.assertEqual(0, len(hist.statistics_scalars))
def testStatisticsScalarsEmpty(self):
b = histogram.HistogramBinBoundaries.CreateLinear(0, 100, 100)
hist = histogram.Histogram('', 'unitless', b)
hist.CustomizeSummaryOptions({
'count': True,
'min': True,
'max': True,
'sum': True,
'avg': True,
'std': True,
'nans': True,
'geometricMean': True,
'percentile': [0, 0.01, 0.1, 0.5, 0.995, 1],
'ci': [0.1, 0.8],
})
stats = hist.statistics_scalars
self.assertEqual(stats['nans'].value, 0)
self.assertEqual(stats['count'].value, 0)
self.assertNotIn('avg', stats)
self.assertNotIn('stddev', stats)
self.assertNotIn('pct_000', stats)
self.assertNotIn('pct_001', stats)
self.assertNotIn('pct_010', stats)
self.assertNotIn('pct_050', stats)
self.assertNotIn('pct_099_5', stats)
self.assertNotIn('pct_100', stats)
self.assertNotIn('ci_010_lower', stats)
self.assertNotIn('ci_010_upper', stats)
self.assertNotIn('ci_010', stats)
self.assertNotIn('ci_080_lower', stats)
self.assertNotIn('ci_080_upper', stats)
self.assertNotIn('ci_080', stats)
def testSampleValues(self):
hist0 = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
hist1 = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
self.assertEqual(hist0.max_num_sample_values, 120)
self.assertEqual(hist1.max_num_sample_values, 120)
values0 = []
values1 = []
for i in range(10):
values0.append(i)
hist0.AddSample(i)
values1.append(10 + i)
hist1.AddSample(10 + i)
self.assertDeepEqual(hist0.sample_values, values0)
self.assertDeepEqual(hist1.sample_values, values1)
hist0.AddHistogram(hist1)
self.assertDeepEqual(hist0.sample_values, values0 + values1)
hist2 = hist0.Clone()
self.assertDeepEqual(hist2.sample_values, values0 + values1)
for i in range(200):
hist0.AddSample(i)
self.assertEqual(len(hist0.sample_values), hist0.max_num_sample_values)
hist3 = histogram.Histogram('', 'unitless', self.TEST_BOUNDARIES)
hist3.max_num_sample_values = 10
for i in range(100):
hist3.AddSample(i)
self.assertEqual(len(hist3.sample_values), 10)
def testSingularBin(self):
hist = histogram.Histogram(
'', 'unitless', histogram.HistogramBinBoundaries.SINGULAR)
self.assertEqual(1, len(hist.bins))
d = hist.AsDict()
self.assertNotIn('binBoundaries', d)
clone = histogram.Histogram.FromDict(d)
self.assertEqual(1, len(clone.bins))
self.assertDeepEqual(d, clone.AsDict())
self.assertEqual(0, hist.GetApproximatePercentile(0))
self.assertEqual(0, hist.GetApproximatePercentile(1))
hist.AddSample(0)
self.assertEqual(0, hist.GetApproximatePercentile(0))
self.assertEqual(0, hist.GetApproximatePercentile(1))
hist.AddSample(1)
self.assertEqual(0, hist.GetApproximatePercentile(0))
self.assertEqual(1, hist.GetApproximatePercentile(1))
hist.AddSample(2)
self.assertEqual(0, hist.GetApproximatePercentile(0))
self.assertEqual(1, hist.GetApproximatePercentile(0.5))
self.assertEqual(2, hist.GetApproximatePercentile(1))
hist.AddSample(3)
self.assertEqual(0, hist.GetApproximatePercentile(0))
self.assertEqual(1, hist.GetApproximatePercentile(0.5))
self.assertEqual(2, hist.GetApproximatePercentile(0.9))
self.assertEqual(3, hist.GetApproximatePercentile(1))
hist.AddSample(4)
self.assertEqual(0, hist.GetApproximatePercentile(0))
self.assertEqual(1, hist.GetApproximatePercentile(0.4))
self.assertEqual(2, hist.GetApproximatePercentile(0.7))
self.assertEqual(3, hist.GetApproximatePercentile(0.9))
self.assertEqual(4, hist.GetApproximatePercentile(1))
def testFromDictMultithreaded(self):
hdict = {
"allBins": {"23": [1]},
"binBoundaries": [0.001, [1, 100000, 30]],
"name": "foo",
"running": [1, 1, 1, 1, 1, 1, 0],
"sampleValues": [1],
"unit": "ms",
}
pool = ThreadPool(10)
histograms = pool.map(histogram.Histogram.FromDict, [hdict] * 10)
self.assertEqual(len(histograms), 10)
for h in histograms:
self.assertEqual(h.name, 'foo')
def testProtoOnlyWritesSummaryOptionsIfNotDefault(self):
hist = histogram.Histogram('name', 'unitless')
with_defaults = hist.AsProto()
hist.CustomizeSummaryOptions({
'count': True,
'min': False,
'max': True,
'sum': True,
'avg': True,
'std': True,
'nans': True,
'geometricMean': True,
'percentile': [0.5, 1]
})
proto = hist.AsProto()
self.assertFalse(with_defaults.HasField('summary_options'))
self.assertTrue(proto.HasField('summary_options'))
def testProtoRoundtrip(self):
generic = generic_set.GenericSet(['generic diagnostic'])
hist = histogram.Histogram(
'name', 'count_smallerIsBetter', self.TEST_BOUNDARIES)
hist.diagnostics['foo'] = generic
hist.CustomizeSummaryOptions({
'count': True,
'min': False,
})
hist.max_num_sample_values = 84
hist.description = "desc"
hist.AddSample(17)
hist.AddSample(18)
hist.AddSample(-1)
# TODO(http://crbug.com/1029452): uncomment once proto supports non-float
# samples and nan diagnostics are supported by protos.
# hist.AddSample('i am not a number', diagnostic_map=generic)
clone = histogram.Histogram.FromProto(hist.AsProto())
self.assertEqual(hist.sample_values, clone.sample_values)
self.assertEqual(hist.description, clone.description)
self.assertEqual(len(hist.diagnostics), len(clone.diagnostics))
self.assertEqual(hist.diagnostics['foo'], clone.diagnostics['foo'])
self.assertEqual(list(hist.statistics_scalars.keys()),
list(clone.statistics_scalars.keys()))
self.assertEqual(hist.max_num_sample_values, clone.max_num_sample_values)
class DiagnosticMapUnittest(unittest.TestCase):
def testDisallowReservedNames(self):
diagnostics = histogram.DiagnosticMap()
with self.assertRaises(TypeError):
diagnostics[None] = generic_set.GenericSet(())
with self.assertRaises(TypeError):
diagnostics['generic'] = None
diagnostics[reserved_infos.TRACE_URLS.name] = date_range.DateRange(0)
diagnostics.DisallowReservedNames()
diagnostics[reserved_infos.TRACE_URLS.name] = generic_set.GenericSet(())
with self.assertRaises(TypeError):
diagnostics[reserved_infos.TRACE_URLS.name] = date_range.DateRange(0)
def testResetGuid(self):
generic = generic_set.GenericSet(['generic diagnostic'])
guid1 = generic.guid
generic.ResetGuid()
guid2 = generic.guid
self.assertNotEqual(guid1, guid2)
# TODO(eakuefner): Find a better place for these non-map tests once we
# break up the Python implementation more.
def testInlineSharedDiagnostic(self):
generic = generic_set.GenericSet(['generic diagnostic'])
hist = histogram.Histogram('', 'count')
_ = generic.guid # First access sets guid
hist.diagnostics['foo'] = generic
generic.Inline()
self.assertFalse(generic.has_guid)
hist_dict = hist.AsDict()
diag_dict = hist_dict['diagnostics']['foo']
self.assertIsInstance(diag_dict, dict)
self.assertEqual(diag_dict['type'], 'GenericSet')
def testCloneWithRef(self):
diagnostics = histogram.DiagnosticMap()
diagnostics['ref'] = diagnostic_ref.DiagnosticRef('abc')
clone = histogram.DiagnosticMap.FromDict(diagnostics.AsDict())
self.assertIsInstance(clone.get('ref'), diagnostic_ref.DiagnosticRef)
self.assertEqual(clone.get('ref').guid, 'abc')
def testDiagnosticGuidDeserialized(self):
d = {
'type': 'GenericSet',
'values': [],
'guid': 'bar'
}
g = diagnostic.Diagnostic.FromDict(d)
self.assertEqual('bar', g.guid)
def testMerge(self):
events = related_event_set.RelatedEventSet()
events.Add({
'stableId': '0.0',
'title': 'foo',
'start': 0,
'duration': 1,
})
generic = generic_set.GenericSet(['generic diagnostic'])
generic2 = generic_set.GenericSet(['generic diagnostic 2'])
related_map = related_name_map.RelatedNameMap()
related_map.Set('a', 'histogram')
hist = histogram.Histogram('', 'count')
# When Histograms are merged, first an empty clone is created with an empty
# DiagnosticMap.
hist2 = histogram.Histogram('', 'count')
hist2.diagnostics['a'] = generic
hist.diagnostics.Merge(hist2.diagnostics)
self.assertIs(generic, hist.diagnostics['a'])
# Separate keys are not merged.
hist3 = histogram.Histogram('', 'count')
hist3.diagnostics['b'] = generic2
hist.diagnostics.Merge(hist3.diagnostics)
self.assertIs(generic, hist.diagnostics['a'])
self.assertIs(generic2, hist.diagnostics['b'])
# Merging unmergeable diagnostics should produce an
# UnmergeableDiagnosticSet.
hist4 = histogram.Histogram('', 'count')
hist4.diagnostics['a'] = related_map
hist.diagnostics.Merge(hist4.diagnostics)
self.assertIsInstance(hist.diagnostics['a'], ums.UnmergeableDiagnosticSet)
diagnostics = list(hist.diagnostics['a'])
self.assertIs(generic, diagnostics[0])
self.assertIs(related_map, diagnostics[1])
# UnmergeableDiagnosticSets are mergeable.
hist5 = histogram.Histogram('', 'count')
hist5.diagnostics['a'] = ums.UnmergeableDiagnosticSet([events, generic2])
hist.diagnostics.Merge(hist5.diagnostics)
self.assertIsInstance(hist.diagnostics['a'], ums.UnmergeableDiagnosticSet)
diagnostics = list(hist.diagnostics['a'])
self.assertIs(generic, diagnostics[0])
self.assertIs(related_map, diagnostics[1])
self.assertIs(events, diagnostics[2])
self.assertIs(generic2, diagnostics[3])