Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/benchmark.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface BenchmarkOptions {
timeout?: number
/** Skip this benchmark */
skip?: boolean
/** Number of warmup iterations to run before the benchmark (default: 0) */
warmup?: number
}

/**
Expand Down
11 changes: 10 additions & 1 deletion src/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ let gcWarned = false
export async function benchmark(name, options, fn) {
if (typeof options === 'function') [fn, options] = [options, undefined]
if (options?.skip) return
const { args, timeout = 1000 } = options ?? {}
const { args, timeout = 1000, warmup = 0 } = options ?? {}

// This will pause us for a bit, but we don't care - having a non-busy process is more important
await new Promise((resolve) => setTimeout(resolve, 0))
Expand All @@ -34,6 +34,15 @@ export async function benchmark(name, options, fn) {
console.log('Warning: no gc() available\n')
}

// Warmup iterations
if (warmup > 0) {
for (let i = 0; i < warmup; i++) {
const arg = args ? args[i % args.length] : i
const val = fn(arg)
if (val instanceof Promise) await val
}
}

let min, max
let total = 0n
let count = 0
Expand Down
118 changes: 118 additions & 0 deletions tests/benchmark.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { test } from 'node:test'
import { strict as assert } from 'node:assert'
import { benchmark } from '../src/benchmark.js'

test('benchmark with warmup option', async () => {
let callCount = 0
const fn = () => {
callCount++
}

// Capture console.log output
const originalLog = console.log
let logged = ''
console.log = (msg) => {
logged += msg + '\n'
}

try {
await benchmark('test warmup', { warmup: 5, timeout: 10 }, fn)

// At least 5 warmup calls should have been made plus some benchmark calls
assert(callCount > 5, `Expected callCount > 5, got ${callCount}`)

// Check that benchmark output was logged
assert(logged.includes('test warmup'), 'Expected benchmark output')
} finally {
console.log = originalLog
}
})

test('benchmark without warmup option', async () => {
let callCount = 0
const fn = () => {
callCount++
}

// Capture console.log output
const originalLog = console.log
console.log = () => {} // Suppress output

try {
await benchmark('test no warmup', { timeout: 10 }, fn)

// Only benchmark calls should have been made (no warmup)
assert(callCount > 0, `Expected callCount > 0, got ${callCount}`)
} finally {
console.log = originalLog
}
})

test('benchmark warmup with args', async () => {
const callArgs = []
const fn = (arg) => {
callArgs.push(arg)
}

// Capture console.log output
const originalLog = console.log
console.log = () => {} // Suppress output

try {
const args = ['a', 'b', 'c']
await benchmark('test warmup with args', { args, warmup: 7, timeout: 10 }, fn)

// Check that warmup used the args in the correct order (cycling through)
// First 7 calls are warmup: a, b, c, a, b, c, a
assert.strictEqual(callArgs[0], 'a')
assert.strictEqual(callArgs[1], 'b')
assert.strictEqual(callArgs[2], 'c')
assert.strictEqual(callArgs[3], 'a')
assert.strictEqual(callArgs[4], 'b')
assert.strictEqual(callArgs[5], 'c')
assert.strictEqual(callArgs[6], 'a')
} finally {
console.log = originalLog
}
})

test('benchmark warmup with async function', async () => {
let callCount = 0
const fn = async () => {
callCount++
await new Promise((resolve) => setTimeout(resolve, 1))
}

// Capture console.log output
const originalLog = console.log
console.log = () => {} // Suppress output

try {
await benchmark('test async warmup', { warmup: 3, timeout: 10 }, fn)

// At least 3 warmup calls should have been made plus some benchmark calls
assert(callCount > 3, `Expected callCount > 3, got ${callCount}`)
} finally {
console.log = originalLog
}
})

test('benchmark warmup with zero value', async () => {
let callCount = 0
const fn = () => {
callCount++
}

// Capture console.log output
const originalLog = console.log
console.log = () => {} // Suppress output

try {
await benchmark('test zero warmup', { warmup: 0, timeout: 10 }, fn)

// Only benchmark calls should have been made (no warmup)
assert(callCount > 0, `Expected callCount > 0, got ${callCount}`)
} finally {
console.log = originalLog
}
})
Loading