Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(bench): do not group benchmarks #2016

Merged
merged 3 commits into from Sep 10, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 1 addition & 15 deletions packages/vitest/src/runtime/map.ts
@@ -1,9 +1,8 @@
import type { Awaitable, BenchFactory, BenchFunction, Benchmark, Suite, SuiteHooks, Test } from '../types'
import type { Awaitable, BenchFunction, Benchmark, Suite, SuiteHooks, Test } from '../types'

// use WeakMap here to make the Test and Suite object serializable
const fnMap = new WeakMap()
const hooksMap = new WeakMap()
const benchmarkMap = new WeakMap()

export function setFn(key: Test | Benchmark, fn: (() => Awaitable<void>) | BenchFunction) {
fnMap.set(key, fn)
Expand All @@ -24,16 +23,3 @@ export function getHooks(key: Suite): SuiteHooks {
export function isTest(task: Test | Benchmark): task is Test {
return task.type === 'test'
}

export async function getBenchmarkFactory(key: Suite): Promise<BenchFactory> {
let benchmark = benchmarkMap.get(key)
if (!benchmark) {
if (!globalThis.EventTarget)
await import('event-target-polyfill' as any)

const Bench = (await import('tinybench')).default
benchmark = new Bench({})
benchmarkMap.set(key, benchmark)
}
return benchmark
}
58 changes: 38 additions & 20 deletions packages/vitest/src/runtime/run.ts
@@ -1,16 +1,23 @@
import { performance } from 'perf_hooks'
import limit from 'p-limit'
import type { Benchmark, BenchmarkResult, File, HookCleanupCallback, HookListener, ResolvedConfig, Suite, SuiteHooks, Task, TaskResult, TaskState, Test } from '../types'
import type { BenchTask, Benchmark, BenchmarkResult, File, HookCleanupCallback, HookListener, ResolvedConfig, Suite, SuiteHooks, Task, TaskResult, TaskState, Test } from '../types'
import { vi } from '../integrations/vi'
import { clearTimeout, createDefer, getFullName, getWorkerState, hasFailed, hasTests, isBrowser, isNode, isRunningInBenchmark, partitionSuiteChildren, setTimeout, shuffle } from '../utils'
import { getState, setState } from '../integrations/chai/jest-expect'
import { GLOBAL_EXPECT } from '../integrations/chai/constants'
import { takeCoverageInsideWorker } from '../integrations/coverage'
import { getBenchmarkFactory, getFn, getHooks } from './map'
import { getFn, getHooks } from './map'
import { rpc } from './rpc'
import { collectTests } from './collect'
import { processError } from './error'

async function importTinybench() {
if (!globalThis.EventTarget)
await import('event-target-polyfill' as any)

return (await import('tinybench'))
}

const now = Date.now

function updateSuiteHookState(suite: Task, name: keyof SuiteHooks, state: TaskState) {
Expand Down Expand Up @@ -295,6 +302,7 @@ function createBenchmarkResult(name: string): BenchmarkResult {
}

async function runBenchmarkSuit(suite: Suite) {
const { Task, Bench } = await importTinybench()
const start = performance.now()

const benchmarkGroup = []
Expand All @@ -310,7 +318,6 @@ async function runBenchmarkSuit(suite: Suite) {
await Promise.all(benchmarkSuiteGroup.map(subSuite => runBenchmarkSuit(subSuite)))

if (benchmarkGroup.length) {
const benchmarkInstance = await getBenchmarkFactory(suite)
const defer = createDefer()
const benchmarkMap: Record<string, Benchmark> = {}
suite.result = {
Expand All @@ -320,33 +327,49 @@ async function runBenchmarkSuit(suite: Suite) {
}
updateTask(suite)
benchmarkGroup.forEach((benchmark, idx) => {
const benchmarkInstance = new Bench(benchmark.options)

const benchmarkFn = getFn(benchmark)

benchmark.result = {
state: 'run',
startTime: start,
benchmark: createBenchmarkResult(benchmark.name),
}
const id = idx.toString()
benchmarkMap[id] = benchmark
benchmarkInstance.add(id, benchmarkFn)

const task = new Task(benchmarkInstance, id, benchmarkFn)
benchmark.task = task
updateTask(benchmark)
})
benchmarkInstance.addEventListener('cycle', (e) => {
const task = e.task
const benchmark = benchmarkMap[task.name || '']
if (benchmark) {
const taskRes = task.result!
const result = benchmark.result!.benchmark!
Object.assign(result, taskRes)
updateTask(benchmark)
}

benchmarkGroup.forEach((benchmark) => {
benchmark.task!.addEventListener('complete', (e) => {
const task = e.task
const _benchmark = benchmarkMap[task.name || '']
if (_benchmark) {
const taskRes = task.result!
const result = _benchmark.result!.benchmark!
Object.assign(result, taskRes)
updateTask(_benchmark)
}
})
benchmark.task!.addEventListener('error', (e) => {
defer.reject(e)
})
})

benchmarkInstance.addEventListener('complete', () => {
Promise.all(benchmarkGroup.map(async (benchmark) => {
await benchmark.task!.warmup()
return await new Promise<BenchTask>(resolve => setTimeout(async () => {
resolve(await benchmark.task!.run())
}))
})).then((tasks) => {
suite.result!.duration = performance.now() - start
suite.result!.state = 'pass'

benchmarkInstance.tasks
tasks
.sort((a, b) => a.result!.mean - b.result!.mean)
.forEach((cycle, idx) => {
const benchmark = benchmarkMap[cycle.name || '']
Expand All @@ -361,11 +384,6 @@ async function runBenchmarkSuit(suite: Suite) {
defer.resolve(null)
})

benchmarkInstance.addEventListener('error', (e) => {
defer.reject(e)
})

benchmarkInstance.run()
await defer
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/types/benchmark.ts
Expand Up @@ -36,6 +36,7 @@ export interface Benchmark extends TaskBase {
suite: Suite
result?: TaskResult
fails?: boolean
task?: BenchTask
options: BenchOptions
}

Expand Down