Skip to content

Commit ad1c0a7

Browse files
committed
test: add retry logic for eventloopdelay histogram sampling
On some build configurations (e.g., sharedlibs), the histogram may not record valid samples (min > 0) after the initial spinning period. This adds a retry mechanism that will spin the event loop additional times if valid samples haven't been recorded yet. This helps ensure the test passes on slower or differently-configured systems where event loop delay sampling may take longer to produce measurable results. Refs: nodejs/reliability#1461
1 parent 3b69757 commit ad1c0a7

File tree

1 file changed

+62
-45
lines changed

1 file changed

+62
-45
lines changed

test/sequential/test-performance-eventloopdelay.js

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
const common = require('../common');
55
const assert = require('assert');
6-
const os = require('os');
76
const {
87
monitorEventLoopDelay,
98
} = require('perf_hooks');
@@ -52,59 +51,77 @@ const { sleep } = require('internal/util');
5251
}
5352

5453
{
55-
const s390x = os.arch() === 's390x';
5654
const histogram = monitorEventLoopDelay({ resolution: 1 });
5755
histogram.enable();
58-
let m = 5;
59-
if (s390x) {
60-
m = m * 2;
56+
57+
// Check if histogram has recorded valid samples (min > 0 indicates real delays measured)
58+
function hasValidSamples() {
59+
return histogram.count > 0 && histogram.min > 0 && histogram.max > 0;
6160
}
61+
62+
// Spin the event loop with blocking work to generate measurable delays.
63+
// Some configurations (s390x, sharedlibs) need more iterations.
64+
let spinsRemaining = 5;
65+
const maxRetries = 3;
66+
let retries = 0;
67+
6268
function spinAWhile() {
6369
sleep(1000);
64-
if (--m > 0) {
70+
if (--spinsRemaining > 0) {
6571
setTimeout(spinAWhile, common.platformTimeout(500));
6672
} else {
67-
// Give the histogram a chance to record final samples before disabling.
68-
// This helps on slower systems where sampling may be delayed.
69-
setImmediate(common.mustCall(() => {
70-
histogram.disable();
71-
// The values are non-deterministic, so we just check that a value is
72-
// present, as opposed to a specific value.
73-
assert(histogram.count > 0, `Expected samples to be recorded, got count=${histogram.count}`);
74-
assert(histogram.min > 0);
75-
assert(histogram.max > 0);
76-
assert(histogram.stddev > 0);
77-
assert(histogram.mean > 0);
78-
assert(histogram.percentiles.size > 0);
79-
for (let n = 1; n < 100; n = n + 0.1) {
80-
assert(histogram.percentile(n) >= 0);
73+
// Give the histogram a chance to record final samples before checking.
74+
setImmediate(() => {
75+
// If we don't have valid samples yet, retry with more spinning.
76+
// This handles slower configurations like sharedlibs builds.
77+
if (!hasValidSamples() && retries < maxRetries) {
78+
retries++;
79+
spinsRemaining = 5;
80+
setTimeout(spinAWhile, common.platformTimeout(500));
81+
return;
8182
}
82-
histogram.reset();
83-
assert.strictEqual(histogram.min, 9223372036854776000);
84-
assert.strictEqual(histogram.max, 0);
85-
assert(Number.isNaN(histogram.stddev));
86-
assert(Number.isNaN(histogram.mean));
87-
assert.strictEqual(histogram.percentiles.size, 1);
8883

89-
['a', false, {}, []].forEach((i) => {
90-
assert.throws(
91-
() => histogram.percentile(i),
92-
{
93-
name: 'TypeError',
94-
code: 'ERR_INVALID_ARG_TYPE',
95-
}
96-
);
97-
});
98-
[-1, 0, 101, NaN].forEach((i) => {
99-
assert.throws(
100-
() => histogram.percentile(i),
101-
{
102-
name: 'RangeError',
103-
code: 'ERR_OUT_OF_RANGE',
104-
}
105-
);
106-
});
107-
}));
84+
// Wrap final assertions in mustCall to ensure they run
85+
common.mustCall(() => {
86+
histogram.disable();
87+
// The values are non-deterministic, so we just check that a value is
88+
// present, as opposed to a specific value.
89+
assert(histogram.count > 0, `Expected samples to be recorded, got count=${histogram.count}`);
90+
assert(histogram.min > 0, `Expected min > 0, got ${histogram.min}`);
91+
assert(histogram.max > 0);
92+
assert(histogram.stddev > 0);
93+
assert(histogram.mean > 0);
94+
assert(histogram.percentiles.size > 0);
95+
for (let n = 1; n < 100; n = n + 0.1) {
96+
assert(histogram.percentile(n) >= 0);
97+
}
98+
histogram.reset();
99+
assert.strictEqual(histogram.min, 9223372036854776000);
100+
assert.strictEqual(histogram.max, 0);
101+
assert(Number.isNaN(histogram.stddev));
102+
assert(Number.isNaN(histogram.mean));
103+
assert.strictEqual(histogram.percentiles.size, 1);
104+
105+
['a', false, {}, []].forEach((i) => {
106+
assert.throws(
107+
() => histogram.percentile(i),
108+
{
109+
name: 'TypeError',
110+
code: 'ERR_INVALID_ARG_TYPE',
111+
}
112+
);
113+
});
114+
[-1, 0, 101, NaN].forEach((i) => {
115+
assert.throws(
116+
() => histogram.percentile(i),
117+
{
118+
name: 'RangeError',
119+
code: 'ERR_OUT_OF_RANGE',
120+
}
121+
);
122+
});
123+
})();
124+
});
108125
}
109126
}
110127
spinAWhile();

0 commit comments

Comments
 (0)