blob: 4c756216d3cbe70ec09dd4b3b55d314cb1da8777 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright 2016 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.
-->
<link rel="import" href="/tracing/value/diagnostics/generic.html">
<link rel="import" href="/tracing/value/histogram.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
var unitlessNumber = tr.b.Unit.byName.unitlessNumber;
var unitlessNumber_sIB = tr.b.Unit.byName.unitlessNumber_smallerIsBetter;
var TEST_BOUNDARIES = tr.v.HistogramBinBoundaries.createLinear(0, 1000, 10);
function checkBoundaries(boundaries, expectedMinBoundary, expectedMaxBoundary,
expectedUnit, expectedBinRanges) {
assert.strictEqual(boundaries.minBinBoundary, expectedMinBoundary);
assert.strictEqual(boundaries.maxBinBoundary, expectedMaxBoundary);
// Check that the boundaries can be used multiple times.
for (var i = 0; i < 3; i++) {
var numeric = new tr.v.Histogram('', expectedUnit, boundaries);
assert.instanceOf(numeric, tr.v.Histogram);
assert.strictEqual(numeric.unit, expectedUnit);
assert.strictEqual(numeric.numValues, 0);
assert.lengthOf(numeric.allBins, expectedBinRanges.length);
for (var j = 0; j < expectedBinRanges.length; j++) {
var bin = numeric.allBins[j];
assert.strictEqual(bin.count, 0);
assert.isTrue(bin.range.equals(expectedBinRanges[j]));
}
}
}
test('significance', function() {
assert.strictEqual(
new tr.v.Histogram('', unitlessNumber).getDifferenceSignificance(
new tr.v.Histogram('', unitlessNumber)), tr.v.Significance.DONT_CARE);
var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 10);
var numericA = new tr.v.Histogram('', unitlessNumber_sIB, boundaries);
var numericB = new tr.v.Histogram('', unitlessNumber_sIB, boundaries);
for (var i = 0; i < 100; ++i) {
numericA.addSample(i);
numericB.addSample(i * 0.85);
}
assert.strictEqual(numericA.getDifferenceSignificance(numericB),
tr.v.Significance.INSIGNIFICANT);
assert.strictEqual(numericB.getDifferenceSignificance(numericA),
tr.v.Significance.INSIGNIFICANT);
assert.strictEqual(numericA.getDifferenceSignificance(numericB, 0.1),
tr.v.Significance.SIGNIFICANT);
assert.strictEqual(numericB.getDifferenceSignificance(numericA, 0.1),
tr.v.Significance.SIGNIFICANT);
});
test('numericBasic', function() {
var n = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
assert.equal(n.getBinForValue(250).range.min, 200);
assert.equal(n.getBinForValue(250).range.max, 300);
n.addSample(-1, {foo: new tr.v.d.Generic('a')});
n.addSample(0, {foo: new tr.v.d.Generic('b')});
n.addSample(0, {foo: new tr.v.d.Generic('c')});
n.addSample(500, {foo: new tr.v.d.Generic('c')});
n.addSample(999, {foo: new tr.v.d.Generic('d')});
n.addSample(1000, {foo: new tr.v.d.Generic('d')});
assert.equal(n.underflowBin.count, 1);
assert.equal(n.getBinForValue(0).count, 2);
assert.deepEqual(
n.getBinForValue(0).diagnosticMaps.map(dm => dm.get('foo').value),
['b', 'c']);
assert.equal(n.getBinForValue(500).count, 1);
assert.equal(n.getBinForValue(999).count, 1);
assert.equal(n.overflowBin.count, 1);
assert.equal(n.numValues, 6);
assert.closeTo(n.average, 416.3, 0.1);
});
test('numericNans', function() {
var n = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
n.addSample(undefined, {foo: new tr.v.d.Generic('b')});
n.addSample(NaN, {'foo': new tr.v.d.Generic('c')});
n.addSample(undefined);
n.addSample(NaN);
assert.equal(n.numNans, 4);
assert.deepEqual(n.nanDiagnosticMaps.map(dm => dm.get('foo').value),
['b', 'c']);
var n2 = n.clone();
assert.instanceOf(n2.nanDiagnosticMaps[0], tr.v.d.DiagnosticMap);
assert.instanceOf(n2.nanDiagnosticMaps[0].get('foo'), tr.v.d.Generic);
});
test('addHistogramsValid', function() {
var n0 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
var n1 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
n0.addSample(-1, {foo: new tr.v.d.Generic('a0')});
n0.addSample(0, {foo: new tr.v.d.Generic('b0')});
n0.addSample(0, {foo: new tr.v.d.Generic('c0')});
n0.addSample(500, {foo: new tr.v.d.Generic('c0')});
n0.addSample(1000, {foo: new tr.v.d.Generic('d0')});
n0.addSample(NaN, {foo: new tr.v.d.Generic('e0')});
n1.addSample(-1, {foo: new tr.v.d.Generic('a1')});
n1.addSample(0, {foo: new tr.v.d.Generic('b1')});
n1.addSample(0, {foo: new tr.v.d.Generic('c1')});
n1.addSample(999, {foo: new tr.v.d.Generic('d1')});
n1.addSample(1000, {foo: new tr.v.d.Generic('d1')});
n1.addSample(NaN, {foo: new tr.v.d.Generic('e1')});
n0.addHistogram(n1);
assert.equal(n0.numNans, 2);
assert.deepEqual(n0.nanDiagnosticMaps.map(dmd => dmd.get('foo').value),
['e0', 'e1']);
assert.equal(n0.underflowBin.count, 2);
assert.deepEqual(
n0.underflowBin.diagnosticMaps.map(dmd => dmd.get('foo').value),
['a0', 'a1']);
assert.equal(n0.getBinForValue(0).count, 4);
assert.deepEqual(
n0.getBinForValue(0).diagnosticMaps.map(dmd => dmd.get('foo').value),
['b0', 'c0', 'b1', 'c1']);
assert.equal(n0.getBinForValue(500).count, 1);
assert.deepEqual(
n0.getBinForValue(500).diagnosticMaps.map(dmd => dmd.get('foo').value),
['c0']);
assert.equal(n0.getBinForValue(999).count, 1);
assert.deepEqual(
n0.getBinForValue(999).diagnosticMaps.map(dmd => dmd.get('foo').value),
['d1']);
assert.equal(n0.overflowBin.count, 2);
assert.deepEqual(
n0.overflowBin.diagnosticMaps.map(dmd => dmd.get('foo').value),
['d0', 'd1']);
assert.equal(n0.numValues, 10);
assert.closeTo(n0.average, 349.7, 0.1);
assert.equal(2, n0.maxCount);
assert.equal(2, n1.maxCount);
var n02 = n0.clone();
assert.instanceOf(n02.underflowBin.diagnosticMaps[0], tr.v.d.DiagnosticMap);
assert.instanceOf(n02.underflowBin.diagnosticMaps[0].get('foo'),
tr.v.d.Generic);
});
test('addHistogramsInvalid', function() {
var n0 = new tr.v.Histogram('', tr.b.Unit.byName.timeDurationInMs,
tr.v.HistogramBinBoundaries.createLinear(0, 1000, 10));
var n1 = new tr.v.Histogram('', tr.b.Unit.byName.timeDurationInMs,
tr.v.HistogramBinBoundaries.createLinear(0, 1001, 10));
var n2 = new tr.v.Histogram('', tr.b.Unit.byName.timeDurationInMs,
tr.v.HistogramBinBoundaries.createLinear(0, 1000, 11));
assert.isFalse(n0.canAddHistogram(n1));
assert.isFalse(n0.canAddHistogram(n2));
assert.isFalse(n1.canAddHistogram(n0));
assert.isFalse(n1.canAddHistogram(n2));
assert.isFalse(n2.canAddHistogram(n0));
assert.isFalse(n2.canAddHistogram(n1));
assert.throws(n0.addHistogram.bind(n0, n1), Error);
assert.throws(n0.addHistogram.bind(n0, n2), Error);
});
test('addHistogramWithNonDiagnosticMapThrows', function() {
var n = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
assert.throws(n.addSample.bind(42, 'foo'), Error);
});
test('numericPercentile', function() {
function check(array, min, max, bins, precision) {
var boundaries = tr.v.HistogramBinBoundaries.createLinear(min, max, bins);
var n = new tr.v.Histogram(
'', tr.b.Unit.byName.timeDurationInMs, boundaries);
array.forEach((x) => n.addSample(x, {foo: new tr.v.d.Generic('x')}));
[0.25, 0.5, 0.75, 0.8, 0.95, 0.99].forEach(function(percent) {
var expected = tr.b.Statistics.percentile(array, percent);
var actual = n.getApproximatePercentile(percent);
assert.closeTo(expected, actual, 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);
var array = [];
for (var i = 0; i < 1000; i++)
array.push((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);
});
test('histogramBinBoundaries_addBinBoundary', function() {
var b = new tr.v.HistogramBinBoundaries(-100);
b.addBinBoundary(50);
checkBoundaries(b, -100, 50, tr.b.Unit.byName.timeDurationInMs, [
tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -100),
tr.b.Range.fromExplicitRange(-100, 50),
tr.b.Range.fromExplicitRange(50, Number.MAX_VALUE)
]);
b.addBinBoundary(60);
b.addBinBoundary(75);
checkBoundaries(b, -100, 75, tr.b.Unit.byName.timeDurationInMs, [
tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -100),
tr.b.Range.fromExplicitRange(-100, 50),
tr.b.Range.fromExplicitRange(50, 60),
tr.b.Range.fromExplicitRange(60, 75),
tr.b.Range.fromExplicitRange(75, Number.MAX_VALUE)
]);
});
test('histogramBinBoundaries_addLinearBins', function() {
var b = new tr.v.HistogramBinBoundaries(1000);
b.addLinearBins(1200, 5);
checkBoundaries(b, 1000, 1200, tr.b.Unit.byName.powerInWatts, [
tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 1000),
tr.b.Range.fromExplicitRange(1000, 1040),
tr.b.Range.fromExplicitRange(1040, 1080),
tr.b.Range.fromExplicitRange(1080, 1120),
tr.b.Range.fromExplicitRange(1120, 1160),
tr.b.Range.fromExplicitRange(1160, 1200),
tr.b.Range.fromExplicitRange(1200, Number.MAX_VALUE)
]);
});
test('histogramBinBoundaries_addExponentialBins', function() {
var b = new tr.v.HistogramBinBoundaries(0.5);
b.addExponentialBins(8, 4);
checkBoundaries(b, 0.5, 8, tr.b.Unit.byName.energyInJoules, [
tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, 0.5),
tr.b.Range.fromExplicitRange(0.5, 1),
tr.b.Range.fromExplicitRange(1, 2),
tr.b.Range.fromExplicitRange(2, 4),
tr.b.Range.fromExplicitRange(4, 8),
tr.b.Range.fromExplicitRange(8, Number.MAX_VALUE)
]);
});
test('histogramBinBoundaries_combined', function() {
var b = new tr.v.HistogramBinBoundaries(-273.15);
b.addBinBoundary(-50);
b.addLinearBins(4, 3);
b.addExponentialBins(16, 2);
b.addLinearBins(17, 4);
b.addBinBoundary(100);
checkBoundaries(b, -273.15, 100, tr.b.Unit.byName.unitlessNumber, [
tr.b.Range.fromExplicitRange(-Number.MAX_VALUE, -273.15),
tr.b.Range.fromExplicitRange(-273.15, -50),
tr.b.Range.fromExplicitRange(-50, -32),
tr.b.Range.fromExplicitRange(-32, -14),
tr.b.Range.fromExplicitRange(-14, 4),
tr.b.Range.fromExplicitRange(4, 8),
tr.b.Range.fromExplicitRange(8, 16),
tr.b.Range.fromExplicitRange(16, 16.25),
tr.b.Range.fromExplicitRange(16.25, 16.5),
tr.b.Range.fromExplicitRange(16.5, 16.75),
tr.b.Range.fromExplicitRange(16.75, 17),
tr.b.Range.fromExplicitRange(17, 100),
tr.b.Range.fromExplicitRange(100, Number.MAX_VALUE)
]);
});
test('histogramBinBoundaries_throws', function() {
var b0 = new tr.v.HistogramBinBoundaries(-7);
assert.throws(function() { b0.addBinBoundary(-10 /* must be > -7 */); });
assert.throws(function() { b0.addBinBoundary(-7 /* must be > -7 */); });
assert.throws(function() { b0.addLinearBins(-10 /* must be > -7 */, 10); });
assert.throws(function() { b0.addLinearBins(-7 /* must be > -7 */, 100); });
assert.throws(function() { b0.addLinearBins(10, 0 /* must be > 0 */); });
assert.throws(function() {
// Current max bin boundary (-7) must be positive.
b0.addExponentialBins(16, 4);
});
var b1 = new tr.v.HistogramBinBoundaries(8);
assert.throws(() => b1.addExponentialBins(20, 0 /* must be > 0 */));
assert.throws(() => b1.addExponentialBins(5 /* must be > 8 */, 3));
assert.throws(() => b1.addExponentialBins(8 /* must be > 8 */, 3));
});
test('statisticsScalars', function() {
var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 100);
var n = new tr.v.Histogram('', unitlessNumber, boundaries);
n.addSample(50);
n.addSample(60);
n.addSample(70);
n.addSample('i am not a number');
n.customizeSummaryOptions({
count: true,
min: true,
max: true,
sum: true,
avg: true,
std: true,
nans: true,
geometricMean: true,
percentile: [0.5, 1]
});
var stats = n.statisticsScalars;
assert.strictEqual(stats.get('nans').unit,
tr.b.Unit.byName.count_smallerIsBetter);
assert.strictEqual(stats.get('nans').value, 1);
assert.strictEqual(stats.get('count').unit,
tr.b.Unit.byName.count_smallerIsBetter);
assert.strictEqual(stats.get('count').value, 3);
assert.strictEqual(stats.get('min').unit, n.unit);
assert.strictEqual(stats.get('min').value, 50);
assert.strictEqual(stats.get('max').unit, n.unit);
assert.strictEqual(stats.get('max').value, 70);
assert.strictEqual(stats.get('sum').unit, n.unit);
assert.strictEqual(stats.get('sum').value, 180);
assert.strictEqual(stats.get('avg').unit, n.unit);
assert.strictEqual(stats.get('avg').value, 60);
assert.strictEqual(stats.get('std').value, 10);
assert.strictEqual(stats.get('pct_050').unit, n.unit);
assert.closeTo(stats.get('pct_050').value, 60, 1);
assert.strictEqual(stats.get('pct_100').unit, n.unit);
assert.closeTo(stats.get('pct_100').value, 70, 1);
assert.strictEqual(stats.get('geometricMean').unit, n.unit);
assert.closeTo(stats.get('geometricMean').value, 59.439, 1e-3);
});
test('statisticsScalarsNoSummaryOptions', function() {
var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 100);
var n = new tr.v.Histogram('', unitlessNumber, boundaries);
n.addSample(50);
n.addSample(60);
n.addSample(70);
n.customizeSummaryOptions({
count: false,
min: false,
max: false,
sum: false,
avg: false,
std: false,
percentile: []
});
assert.strictEqual(n.statisticsScalars.size, 0);
});
test('statisticsScalarsEmptyNumericValue', function() {
var boundaries = tr.v.HistogramBinBoundaries.createLinear(0, 100, 100);
var n = new tr.v.Histogram('', unitlessNumber, boundaries);
n.customizeSummaryOptions({
count: true,
min: true,
max: true,
sum: true,
avg: true,
std: true,
percentile: [0, 0.01, 0.1, 0.5, 0.995, 1]
});
var stats = n.statisticsScalars;
assert.strictEqual(stats.get('count').value, 0);
assert.strictEqual(stats.get('min').value, Infinity);
assert.strictEqual(stats.get('max').value, -Infinity);
assert.strictEqual(stats.get('sum').value, 0);
assert.strictEqual(stats.get('avg'), undefined);
assert.strictEqual(stats.get('std'), undefined);
assert.strictEqual(stats.get('pct_000').value, 0);
assert.strictEqual(stats.get('pct_001').value, 0);
assert.strictEqual(stats.get('pct_010').value, 0);
assert.strictEqual(stats.get('pct_050').value, 0);
assert.strictEqual(stats.get('pct_099_5').value, 0);
assert.strictEqual(stats.get('pct_100').value, 0);
});
test('sampleValues', function() {
var n0 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
var n1 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
// maxNumSampleValues defaults to numBins * 10, which, including the
// underflowBin and overflowBin plus this builder's 10 central bins,
// is 12 * 10.
assert.strictEqual(n0.maxNumSampleValues, 120);
assert.strictEqual(n1.maxNumSampleValues, 120);
var values0 = [];
var values1 = [];
for (var i = 0; i < 10; ++i) {
values0.push(i);
n0.addSample(i);
}
for (var i = 10; i < 20; ++i) {
values1.push(i);
n1.addSample(i);
}
assert.deepEqual(n0.sampleValues, values0);
assert.deepEqual(n1.sampleValues, values1);
n0.addHistogram(n1);
assert.deepEqual(n0.sampleValues, values0.concat(values1));
var n2 = n0.clone();
assert.deepEqual(n2.sampleValues, values0.concat(values1));
for (var i = 0; i < 200; ++i)
n0.addSample(i);
assert.strictEqual(n0.sampleValues.length, n0.maxNumSampleValues);
var n3 = new tr.v.Histogram('', unitlessNumber, TEST_BOUNDARIES);
n3.maxNumSampleValues = 10;
for (var i = 0; i < 100; ++i)
n3.addSample(i);
assert.strictEqual(n3.sampleValues.length, 10);
});
});
</script>