Skip to content

Commit 93fabd8

Browse files
committed
feat: Use tracker.
1 parent 5f38231 commit 93fabd8

File tree

3 files changed

+72
-47
lines changed

3 files changed

+72
-47
lines changed

src/models.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { type Histogram } from 'hdr-histogram-js'
21
import { fileURLToPath } from 'node:url'
32
import { type Worker } from 'node:worker_threads'
3+
import { type Tracker } from './tracker.ts'
44

55
export interface PrintOptions {
66
colors?: boolean
@@ -84,7 +84,7 @@ export interface TestContext {
8484
errorThreshold: number
8585
total: number
8686
executed: number
87-
histogram: Histogram
87+
tracker: Tracker
8888
start: bigint
8989
handler: (error?: Error | null) => void
9090
notifier: (value: any) => void

src/tracker.ts

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { build, type Histogram } from 'hdr-histogram-js'
2+
import { percentiles, type Result } from './models.ts'
3+
4+
export class Tracker {
5+
iterations: number
6+
histogram: Histogram
7+
error: Error | undefined
8+
9+
constructor() {
10+
this.iterations = 0
11+
this.error = undefined
12+
this.histogram = build({
13+
lowestDiscernibleValue: 1,
14+
highestTrackableValue: 1e9,
15+
numberOfSignificantValueDigits: 5
16+
})
17+
}
18+
19+
get results(): Result {
20+
if (typeof this.error !== 'undefined') {
21+
return {
22+
success: false,
23+
error: this.error,
24+
size: 0,
25+
min: 0,
26+
max: 0,
27+
mean: 0,
28+
stddev: 0,
29+
percentiles: {},
30+
standardError: 0
31+
}
32+
}
33+
34+
const size = this.iterations
35+
const { minNonZeroValue: min, maxValue: max, mean, stdDeviation } = this.histogram
36+
37+
return {
38+
success: true,
39+
size,
40+
min,
41+
max,
42+
mean,
43+
stddev: stdDeviation,
44+
percentiles: Object.fromEntries(
45+
percentiles.map(percentile => [percentile, this.histogram.getValueAtPercentile(percentile)])
46+
),
47+
standardError: stdDeviation / Math.sqrt(size)
48+
}
49+
}
50+
51+
get standardError(): number {
52+
return this.histogram.stdDeviation / Math.sqrt(this.iterations)
53+
}
54+
55+
track(start: bigint) {
56+
// Grab duration even in case of error to make sure we don't add any overhead to the benchmark
57+
const duration = Number(process.hrtime.bigint() - start)
58+
this.histogram.recordValue(duration)
59+
this.iterations++
60+
}
61+
}

src/worker.ts

+9-45
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
1-
import { build as buildHistogram } from 'hdr-histogram-js'
2-
import {
3-
percentiles,
4-
type Result,
5-
type SetupFunction,
6-
type TestContext,
7-
type TestFunction,
8-
type WorkerContext
9-
} from './models.ts'
1+
import { type Result, type SetupFunction, type TestContext, type TestFunction, type WorkerContext } from './models.ts'
2+
import { Tracker } from './tracker.ts'
103

114
function noOp(): void {
125
// No-op
@@ -17,30 +10,18 @@ function noSetup(cb: (err?: Error | null) => void): void {
1710
}
1811

1912
function handleTestIteration(context: TestContext, error?: Error | null): void {
20-
// Grab duration even in case of error to make sure we don't add any overhead to the benchmark
21-
const duration = Number(process.hrtime.bigint() - context.start)
22-
2313
// Handle error
2414
if (error) {
25-
context.callback({
26-
success: false,
27-
error,
28-
size: 0,
29-
min: 0,
30-
max: 0,
31-
mean: 0,
32-
stddev: 0,
33-
percentiles: {},
34-
standardError: 0
35-
})
15+
context.tracker.error = error
16+
context.callback(context.tracker.results)
3617
return
3718
}
3819

3920
// Get some parameters
40-
const { histogram, total, errorThreshold } = context
21+
const { tracker, total, errorThreshold } = context
4122

4223
// Track results
43-
histogram.recordValue(duration)
24+
tracker.track(context.start)
4425
context.executed++
4526

4627
// Check if stop earlier if we are below the error threshold
@@ -52,7 +33,7 @@ function handleTestIteration(context: TestContext, error?: Error | null): void {
5233

5334
// Check if abort the test earlier. It is checked every 5% after 10% of the iterations
5435
if (completedPercentage >= 1000 && completedPercentage % 500 === 0) {
55-
const standardErrorPercentage = histogram.stdDeviation / Math.sqrt(executed) / histogram.mean
36+
const standardErrorPercentage = tracker.standardError / tracker.histogram.mean
5637

5738
if (standardErrorPercentage < errorThreshold) {
5839
stop = true
@@ -62,20 +43,7 @@ function handleTestIteration(context: TestContext, error?: Error | null): void {
6243

6344
// If the test is over
6445
if (stop || executed > total) {
65-
const stdDev = histogram.stdDeviation
66-
67-
context.callback({
68-
success: true,
69-
size: executed,
70-
min: histogram.minNonZeroValue,
71-
max: histogram.maxValue,
72-
mean: histogram.mean,
73-
stddev: stdDev,
74-
percentiles: Object.fromEntries(
75-
percentiles.map(percentile => [percentile, histogram.getValueAtPercentile(percentile)])
76-
),
77-
standardError: stdDev / Math.sqrt(executed)
78-
})
46+
context.callback(tracker.results)
7947
return
8048
}
8149

@@ -204,11 +172,7 @@ export function runWorker(context: WorkerContext, notifier: (value: any) => void
204172
errorThreshold,
205173
total: iterations - 1,
206174
executed: 0,
207-
histogram: buildHistogram({
208-
lowestDiscernibleValue: 1,
209-
highestTrackableValue: 1e9,
210-
numberOfSignificantValueDigits: 5
211-
}),
175+
tracker: new Tracker(),
212176
start: BigInt(0),
213177
handler: noOp,
214178
notifier,

0 commit comments

Comments
 (0)