Skip to content

Commit c1e2478

Browse files
committed
test: expand histogram test coverage
Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode PR-URL: #65825 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent c327212 commit c1e2478

4 files changed

Lines changed: 120 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const { once } = require('events');
6+
const { Worker } = require('worker_threads');
7+
8+
const worker = new Worker(`
9+
const { parentPort } = require('worker_threads');
10+
const { createHistogram } = require('perf_hooks');
11+
12+
const histogram = createHistogram({ highest: 200000, figures: 5 });
13+
for (let i = 1; i <= 100000; i++) histogram.record(i);
14+
histogram.qrde({ bins: 1000, dequantize: 'all' });
15+
parentPort.postMessage('scheduled');
16+
`, { eval: true });
17+
18+
(async () => {
19+
assert.deepStrictEqual(await once(worker, 'message'), ['scheduled']);
20+
assert.strictEqual(await worker.terminate(), 1);
21+
})().then(common.mustCall());

test/parallel/test-perf-hooks-histogram-qrde.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ function assertClose(actual, expected, tolerance = 1e-12) {
99
`${actual} != ${expected}`);
1010
}
1111

12+
function recordRepeated(histogram, options, value, count) {
13+
const block = createHistogram(options);
14+
block.record(value);
15+
while (count > 0) {
16+
if (count % 2 === 1) histogram.add(block);
17+
count = Math.floor(count / 2);
18+
if (count > 0) block.add(block);
19+
}
20+
}
21+
1222
(async () => {
1323
const empty = createHistogram();
1424
const emptyResult = await empty.qrde();
@@ -23,6 +33,9 @@ function assertClose(actual, expected, tolerance = 1e-12) {
2333
assert.strictEqual(emptyResult.corrections, 0);
2434
assert.strictEqual(emptyResult.dequantize, 'hdr');
2535

36+
assert.throws(() => empty.qrde.call({}), {
37+
code: 'ERR_INVALID_THIS',
38+
});
2639
assert.throws(() => empty.qrde(null), {
2740
code: 'ERR_INVALID_ARG_TYPE',
2841
});
@@ -219,4 +232,18 @@ function assertClose(actual, expected, tolerance = 1e-12) {
219232
await largeCount.qrde({ bins: 2, dequantize: 'none' });
220233
assert.strictEqual(largeCountResult.count, (1n << 53n) + 1n);
221234
assertClose(largeCountResult.quantiles[1], 2);
235+
236+
// Exercise correction across the exact-to-asymptotic beta CDF threshold.
237+
const correctionOptions = { highest: 131071, figures: 5 };
238+
const correction = createHistogram(correctionOptions);
239+
recordRepeated(correction, correctionOptions, 1, 26239);
240+
recordRepeated(correction, correctionOptions, 131071, 973761);
241+
const count = 1_000_000;
242+
const threshold = (1 - Math.sqrt(1 - 100_000 / (count + 1))) / 2;
243+
const corrected = await correction.qrde({
244+
probabilities: [0, threshold - 1e-10, threshold + 1e-10, 1],
245+
dequantize: 'none',
246+
});
247+
assert.strictEqual(corrected.corrections, 1);
248+
assert.strictEqual(corrected.quantiles[1], corrected.quantiles[2]);
222249
})().then(common.mustCall());

test/parallel/test-perf-hooks-sliding-window-histogram.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ const {
4949
assert.strictEqual(histogram.snapshot().count, 0);
5050
histogram.record(10n);
5151
assert.strictEqual(histogram.snapshot().maxBigInt, 10n);
52+
for (const value of [0n, 2n ** 63n]) {
53+
assert.throws(() => histogram.record(value), {
54+
code: 'ERR_OUT_OF_RANGE',
55+
});
56+
}
5257

5358
assert.throws(() => new histogram.constructor(), {
5459
code: 'ERR_ILLEGAL_CONSTRUCTOR',
@@ -142,6 +147,19 @@ const {
142147
highest: 10,
143148
}), { code: 'ERR_OUT_OF_RANGE' });
144149

150+
for (const [name, value] of [
151+
['lowest', 0n],
152+
['lowest', 2n ** 63n],
153+
['highest', 0n],
154+
['highest', 2n ** 63n],
155+
]) {
156+
assert.throws(() => createSlidingWindowHistogram({
157+
chunks: 2,
158+
recordsPerChunk: 1,
159+
[name]: value,
160+
}), { code: 'ERR_OUT_OF_RANGE' });
161+
}
162+
145163
for (const bounds of [
146164
{ lowest: 1n },
147165
{ lowest: 1n, highest: 100 },
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const {
6+
createJSHeapSnapshot,
7+
validateByRetainingPathFromNodes,
8+
} = require('../common/heap');
9+
const {
10+
createHistogram,
11+
createSlidingWindowHistogram,
12+
} = require('perf_hooks');
13+
14+
(async () => {
15+
const uncached = createHistogram();
16+
const cached = createHistogram();
17+
cached.record(1);
18+
cached.record(1000);
19+
await cached.qrde({ cache: true });
20+
21+
const sliding = createSlidingWindowHistogram({
22+
chunks: 2,
23+
recordsPerChunk: 1,
24+
});
25+
26+
const nodes = createJSHeapSnapshot();
27+
const snapshots = validateByRetainingPathFromNodes(
28+
nodes,
29+
'Node / Histogram',
30+
[{ node_name: 'Node / qrde_snapshot', edge_name: 'qrde_snapshot' }],
31+
);
32+
assert.strictEqual(snapshots.length, 1);
33+
assert.ok(snapshots[0].self_size > 0);
34+
35+
const windows = validateByRetainingPathFromNodes(
36+
nodes,
37+
'Node / SlidingWindowHistogram',
38+
[],
39+
);
40+
for (const [edgeName, nodeName] of [
41+
['chunks', 'Node / chunks'],
42+
['generations', 'Node / generations'],
43+
['spare', 'Node / Histogram'],
44+
]) {
45+
validateByRetainingPathFromNodes(windows, 'Node / SlidingWindowHistogram', [
46+
{ node_name: nodeName, edge_name: edgeName },
47+
]);
48+
}
49+
50+
// Keep all three wrappers live through snapshot generation.
51+
assert.strictEqual(uncached.count, 0);
52+
assert.strictEqual(cached.count, 2);
53+
assert.strictEqual(sliding.snapshot().count, 0);
54+
})().then(common.mustCall());

0 commit comments

Comments
 (0)