Skip to content

Commit a0e3c9c

Browse files
authored
fix: accurate results and hooks fix (#43)
* update * update * update
1 parent 30234c5 commit a0e3c9c

File tree

5 files changed

+68
-36
lines changed

5 files changed

+68
-36
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,15 @@ export type BenchEvent = Event & {
352352
};
353353
```
354354

355+
### `process.hrtime`
356+
if you want more accurate results for nodejs with `process.hrtime`, then import
357+
the `hrtimeNow` function from the library and pass it to the `Bench` options.
358+
359+
```ts
360+
import { hrtimeNow } from 'tinybench';
361+
```
362+
It may make your benchmarks slower, check #42.
363+
355364
## Prior art
356365

357366
- [Benchmark.js](https://github.com/bestiejs/benchmark.js)

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export type {
1111
BenchEvent,
1212
} from '../types';
1313

14-
export { now } from './utils';
14+
export { now, hrtimeNow } from './utils';
1515

1616
export { Bench, Task };
1717
export default Bench;

src/task.ts

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import type {
2-
Fn, TaskEvents, TaskResult, TaskEventsMap, FnOptions,
2+
Fn,
3+
TaskEvents,
4+
TaskResult,
5+
TaskEventsMap,
6+
FnOptions,
37
} from '../types/index';
48
import Bench from './bench';
59
import tTable from './constants';
@@ -61,35 +65,33 @@ export default class Task extends EventTarget {
6165
await this.opts.beforeAll.call(this);
6266
}
6367

64-
while (
65-
(totalTime < this.bench.time || this.runs < this.bench.iterations)
66-
&& !this.bench.signal?.aborted
67-
) {
68-
if (this.opts.beforeEach != null) {
69-
await this.opts.beforeEach.call(this);
70-
}
71-
72-
let taskStart = 0;
68+
try {
69+
while (
70+
(totalTime < this.bench.time || this.runs < this.bench.iterations)
71+
&& !this.bench.signal?.aborted
72+
) {
73+
if (this.opts.beforeEach != null) {
74+
await this.opts.beforeEach.call(this);
75+
}
7376

74-
try {
75-
taskStart = this.bench.now();
77+
const taskStart = this.bench.now();
7678
if (isAsync) {
7779
await this.fn();
7880
} else {
7981
this.fn();
8082
}
81-
} catch (e) {
82-
this.setResult({ error: e });
83-
}
83+
const taskTime = this.bench.now() - taskStart;
8484

85-
const taskTime = this.bench.now() - taskStart;
86-
this.runs += 1;
87-
samples.push(taskTime);
88-
totalTime += taskTime;
85+
samples.push(taskTime);
86+
this.runs += 1;
87+
totalTime += taskTime;
8988

90-
if (this.opts.afterEach != null) {
91-
await this.opts.afterEach.call(this);
89+
if (this.opts.afterEach != null) {
90+
await this.opts.afterEach.call(this);
91+
}
9292
}
93+
} catch (e) {
94+
this.setResult({ error: e });
9395
}
9496

9597
if (this.opts.afterAll != null) {
@@ -100,7 +102,7 @@ export default class Task extends EventTarget {
100102

101103
samples.sort((a, b) => a - b);
102104

103-
{
105+
if (!this.result?.error) {
104106
const min = samples[0]!;
105107
const max = samples[samples.length - 1]!;
106108
const period = totalTime / this.runs;
@@ -169,24 +171,46 @@ export default class Task extends EventTarget {
169171
*/
170172
async warmup() {
171173
this.dispatchEvent(createBenchEvent('warmup', this));
174+
const isAsync = isAsyncFunction(this.fn);
172175
const startTime = this.bench.now();
173176
let totalTime = 0;
174177

175178
await this.bench.setup(this, 'warmup');
179+
180+
if (this.opts.beforeAll != null) {
181+
await this.opts.beforeAll.call(this);
182+
}
183+
176184
while (
177185
(totalTime < this.bench.warmupTime
178186
|| this.runs < this.bench.warmupIterations)
179187
&& !this.bench.signal?.aborted
180188
) {
189+
if (this.opts.beforeEach != null) {
190+
await this.opts.beforeEach.call(this);
191+
}
192+
181193
try {
182194
// eslint-disable-next-line no-await-in-loop
183-
await Promise.resolve().then(this.fn);
195+
if (isAsync) {
196+
await this.fn();
197+
} else {
198+
this.fn();
199+
}
184200
} catch {
185201
// todo
186202
}
187203

188204
this.runs += 1;
189205
totalTime = this.bench.now() - startTime;
206+
207+
if (this.opts.afterEach != null) {
208+
await this.opts.afterEach.call(this);
209+
}
210+
}
211+
212+
if (this.opts.afterAll != null) {
213+
await this.opts.afterAll.call(this);
190214
}
191215
this.bench.teardown(this, 'warmup');
192216

src/utils.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@ import type { Fn } from '../types/index';
22

33
export const nanoToMs = (nano: number) => nano / 1e6;
44

5-
export const now = () => {
6-
if (typeof globalThis.process?.hrtime === 'function') {
7-
return nanoToMs(Number(process.hrtime.bigint()));
8-
}
9-
return performance.now();
10-
};
5+
export const hrtimeNow = () => nanoToMs(Number(process.hrtime.bigint()));
6+
7+
export const now = () => performance.now();
118

129
/**
1310
* Computes the arithmetic mean of a sample.

test/index.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,10 @@ test('setup and teardown', async () => {
281281
});
282282

283283
test('task beforeAll, afterAll, beforeEach, afterEach', async () => {
284-
const bench = new Bench({ time: 50 });
284+
const iterations = 100;
285+
const bench = new Bench({
286+
time: 0, warmupTime: 0, iterations, warmupIterations: iterations,
287+
});
285288

286289
const beforeAll = vi.fn(function hook(this: Task) {
287290
expect(this).toBe(bench.getTask('foo'));
@@ -303,14 +306,13 @@ test('task beforeAll, afterAll, beforeEach, afterEach', async () => {
303306
beforeEach,
304307
afterEach,
305308
});
306-
const task = bench.getTask('foo')!;
307309

308310
await bench.warmup();
309311
await bench.run();
310312

311-
expect(beforeAll.mock.calls.length).toBe(1);
312-
expect(afterAll.mock.calls.length).toBe(1);
313-
expect(beforeEach.mock.calls.length).toBe(task.runs);
314-
expect(afterEach.mock.calls.length).toBe(task.runs);
313+
expect(beforeAll.mock.calls.length).toBe(2);
314+
expect(afterAll.mock.calls.length).toBe(2);
315+
expect(beforeEach.mock.calls.length).toBe(iterations * 2 /* warmup + run */);
316+
expect(afterEach.mock.calls.length).toBe(iterations * 2);
315317
expect(beforeEach.mock.calls.length).toBe(afterEach.mock.calls.length);
316318
});

0 commit comments

Comments
 (0)