Skip to content

Commit b11ca93

Browse files
committed
fix(bench): discard autocannon warmup before measuring
1 parent a1f656e commit b11ca93

2 files changed

Lines changed: 47 additions & 11 deletions

File tree

bench/routing/drivers.test.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { describe, expect, it } from 'bun:test'
2-
import { ohaArgs } from './drivers'
1+
import { describe, expect, it, spyOn } from 'bun:test'
2+
import { DRIVERS, ohaArgs } from './drivers'
33

44
describe('oha command', () => {
55
it('applies one global fixed request rate with latency correction', () => {
@@ -18,3 +18,42 @@ describe('oha command', () => {
1818
])
1919
})
2020
})
21+
22+
describe('autocannon warmup', () => {
23+
it.each([0, 3])('discards %s seconds of warmup without changing workers', async (warmupSeconds) => {
24+
const output = (requests: number) => ({
25+
stdout: new Response(JSON.stringify({ requests: { total: requests, average: requests } })).body,
26+
stderr: new Response('').body,
27+
exited: Promise.resolve(0),
28+
}) as unknown as ReturnType<typeof Bun.spawn>
29+
const spawn = spyOn(Bun, 'spawn')
30+
if (warmupSeconds > 0) spawn.mockReturnValueOnce(output(999))
31+
spawn.mockReturnValueOnce(output(42))
32+
try {
33+
const result = await DRIVERS.find(driver => driver.name === 'autocannon')!.run({
34+
url: 'http://127.0.0.1:39400/bench/echo',
35+
method: 'POST',
36+
body: '{"name":"bench","count":7}',
37+
headers: { 'content-type': 'application/json', 'x-bench': 'preserved' },
38+
connections: 7,
39+
warmupSeconds,
40+
durationSeconds: 11,
41+
})
42+
expect(result.requests).toBe(42)
43+
expect(JSON.parse(result.raw).requests.total).toBe(42)
44+
const commands = spawn.mock.calls.map(call => call[0] as string[])
45+
expect(commands.map(args => args[args.indexOf('-d') + 1])).toEqual(warmupSeconds > 0 ? ['3', '11'] : ['11'])
46+
for (const args of commands) {
47+
expect(args).not.toContain('-w')
48+
expect(args[args.indexOf('-c') + 1]).toBe('7')
49+
expect(args[args.indexOf('-m') + 1]).toBe('POST')
50+
expect(args[args.indexOf('-b') + 1]).toBe('{"name":"bench","count":7}')
51+
expect(args).toContain('content-type: application/json')
52+
expect(args).toContain('x-bench: preserved')
53+
}
54+
}
55+
finally {
56+
spawn.mockRestore()
57+
}
58+
})
59+
})

bench/routing/drivers.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,12 @@ const autocannon: Driver = {
172172
supportsFixedRate: false,
173173
isAvailable: () => which('autocannon'),
174174
async run(req) {
175-
const args = ['autocannon', '-d', String(req.durationSeconds), '-w', String(req.warmupSeconds), '-c', String(req.connections), '-j']
176-
if (req.method !== 'GET') {
177-
args.push('-m', req.method)
178-
if (req.body != null) args.push('-b', req.body)
179-
}
180-
for (const [name, value] of Object.entries(req.headers))
181-
args.push('-H', `${name}: ${value}`)
182-
args.push(req.url)
183-
const raw = await capture(args)
175+
const args = ['autocannon', '-c', String(req.connections), '-j', ...methodArgs(req, '-m', '-b', '-H')]
176+
// Keep warmup separate, as in the native adapters. Autocannon's -w
177+
// selects worker threads, not a discarded warmup duration.
178+
if (req.warmupSeconds > 0)
179+
await capture([...args, '-d', String(req.warmupSeconds), req.url])
180+
const raw = await capture([...args, '-d', String(req.durationSeconds), req.url])
184181
const json = JSON.parse(raw)
185182
return {
186183
rpsMean: json.requests?.average ?? 0,

0 commit comments

Comments
 (0)