source: trip-planner-front/node_modules/hdr-histogram-js/src/Histogram.fc.spec.ts@ 188ee53

Last change on this file since 188ee53 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/*
2 * This is a TypeScript port of the original Java version, which was written by
3 * Gil Tene as described in
4 * https://github.com/HdrHistogram/HdrHistogram
5 * and released to the public domain, as explained at
6 * http://creativecommons.org/publicdomain/zero/1.0/
7 */
8import * as fc from "fast-check";
9import * as hdr from "./index";
10import { initWebAssembly } from "./wasm";
11import Histogram, { BitBucketSize } from "./Histogram";
12
13const runFromStryker = __dirname.includes("stryker");
14
15const runnerOptions = {
16 numRuns: runFromStryker ? 10 : 1000,
17 verbose: true,
18};
19
20describe("Histogram percentile computation", () => {
21 beforeAll(initWebAssembly);
22
23 const numberOfSignificantValueDigits = 3;
24 [true, false].forEach((useWebAssembly) =>
25 [16, "packed"].forEach((bitBucketSize: BitBucketSize) =>
26 it(`Histogram ${bitBucketSize} (wasm: ${useWebAssembly}) should be accurate according to its significant figures`, async () => {
27 await initWebAssembly();
28
29 fc.assert(
30 fc.property(arbData(2000), (numbers) => {
31 const histogram = hdr.build({
32 bitBucketSize,
33 numberOfSignificantValueDigits,
34 useWebAssembly,
35 });
36 numbers.forEach((n) => histogram.recordValue(n));
37 const actual = quantile(numbers, 90);
38 const got = histogram.getValueAtPercentile(90);
39 const relativeError = Math.abs(1 - got / actual);
40 const variation = Math.pow(10, -numberOfSignificantValueDigits);
41 histogram.destroy();
42 return relativeError < variation;
43 }),
44 runnerOptions
45 );
46 })
47 )
48 );
49});
50
51describe("Histogram percentile computation (packed vs classic)", () => {
52 const numberOfSignificantValueDigits = 3;
53 const classicHistogram = hdr.build({
54 numberOfSignificantValueDigits,
55 });
56 const histogram = hdr.build({
57 numberOfSignificantValueDigits,
58 bitBucketSize: "packed",
59 useWebAssembly: false,
60 });
61
62 it(`should be accurate according to its significant figures`, () => {
63 fc.assert(
64 fc.property(arbData(5), (numbers) => {
65 histogram.reset();
66 classicHistogram.reset();
67 numbers.forEach((n) => histogram.recordValue(n));
68 numbers.forEach((n) => classicHistogram.recordValue(n));
69 const actual = classicHistogram.getValueAtPercentile(90);
70 const got = histogram.getValueAtPercentile(90);
71 return actual === got;
72 }),
73 runnerOptions
74 );
75 });
76});
77
78describe("Histogram percentile computation with CO correction (wasm vs js)", () => {
79 beforeAll(initWebAssembly);
80
81 let jsHistogram: Histogram;
82 let wasmHistogram: Histogram;
83
84 beforeEach(() => {
85 jsHistogram = hdr.build({
86 useWebAssembly: false,
87 });
88 wasmHistogram = hdr.build({
89 useWebAssembly: true,
90 });
91 });
92
93 afterEach(() => {
94 jsHistogram.destroy();
95 wasmHistogram.destroy();
96 });
97
98 it(`should be accurate according to its significant figures`, () => {
99 fc.assert(
100 fc.property(arbData(1, 100 * 1000), (numbers) => {
101 jsHistogram.reset();
102 wasmHistogram.reset();
103 numbers.forEach((n) => {
104 jsHistogram.recordValueWithExpectedInterval(n, 1000);
105 });
106 numbers.forEach((n) => {
107 wasmHistogram.recordValueWithExpectedInterval(n, 1000);
108 });
109 const js = jsHistogram.getValueAtPercentile(90);
110 const wasm = wasmHistogram.getValueAtPercentile(90);
111 const relativeError = Math.abs(1 - js / wasm);
112 const variation = Math.pow(10, -3);
113 if (relativeError >= variation) {
114 console.log({ js, wasm });
115 }
116 return relativeError < variation;
117 }),
118 runnerOptions
119 );
120 });
121});
122
123describe("Histogram encoding/decoding", () => {
124 beforeAll(initWebAssembly);
125
126 const numberOfSignificantValueDigits = 3;
127 [true, false].forEach((useWebAssembly) =>
128 [8, 16, 32, 64, "packed"].forEach((bitBucketSize: BitBucketSize) => {
129 it(`Histogram ${bitBucketSize} (wasm: ${useWebAssembly}) should keep all data after an encoding/decoding roundtrip`, () => {
130 fc.assert(
131 fc.property(arbData(1), fc.double(50, 100), (numbers, percentile) => {
132 const histogram = hdr.build({
133 bitBucketSize,
134 numberOfSignificantValueDigits,
135 useWebAssembly,
136 });
137 numbers.forEach((n) => histogram.recordValue(n));
138 const encodedHistogram = hdr.encodeIntoCompressedBase64(histogram);
139 const decodedHistogram = hdr.decodeFromCompressedBase64(
140 encodedHistogram
141 );
142 const actual = histogram.getValueAtPercentile(percentile);
143 const got = decodedHistogram.getValueAtPercentile(percentile);
144 histogram.destroy();
145 decodedHistogram.destroy();
146 return actual === got;
147 }),
148 runnerOptions
149 );
150 });
151 })
152 );
153});
154
155const arbData = (size: number, max: number = Number.MAX_SAFE_INTEGER) =>
156 fc.array(fc.integer(1, max), size, size);
157
158// reference implementation
159const quantile = (inputData: number[], percentile: number) => {
160 const data = [...inputData].sort((a, b) => a - b);
161 const index = (percentile / 100) * (data.length - 1);
162 let result: number;
163 if (Math.floor(index) === index) {
164 result = data[index];
165 } else {
166 const i = Math.floor(index);
167 const fraction = index - i;
168 result = data[i] + (data[i + 1] - data[i]) * fraction;
169 }
170 return result;
171};
Note: See TracBrowser for help on using the repository browser.