fix: replace plimit with own promises limiter implementation to plug … · tinylibs/tinybench@6d93a1e
1-import pLimit from 'p-limit'
2-31import type {
42AddEventListenerOptionsArgument,
53BenchEvents,
@@ -26,7 +24,7 @@ import {
2624defaultConvertTaskResultForConsoleTable,
2725invariant,
2826type JSRuntime,
29-now,
27+performanceNow,
3028runtime,
3129runtimeVersion,
3230} from './utils'
@@ -109,10 +107,13 @@ export class Bench extends EventTarget {
109107this.name = name
110108this.runtime = runtime
111109this.runtimeVersion = runtimeVersion
110+this.concurrency = restOptions.concurrency ?? null
111+this.threshold = restOptions.threshold ?? Infinity
112+112113this.opts = {
113114 ...{
114115iterations: defaultMinimumIterations,
115- now,
116+now: performanceNow,
116117setup: emptyFunction,
117118teardown: emptyFunction,
118119throws: false,
@@ -122,6 +123,8 @@ export class Bench extends EventTarget {
122123warmupTime: defaultMinimumWarmupTime,
123124},
124125 ...restOptions,
126+ ...(restOptions.iterations !== undefined && restOptions.time === undefined && { time: 0 }),
127+ ...(restOptions.warmupIterations !== undefined && restOptions.warmupTime === undefined && { warmupTime: 0 }),
125128}
126129127130if (this.opts.signal) {
@@ -195,15 +198,23 @@ export class Bench extends EventTarget {
195198if (this.opts.warmup) {
196199await this.#warmupTasks()
197200}
198- let values: Task[] = []
201+199202this.dispatchEvent(new BenchEvent('start'))
203+204+let values: Task[] = []
205+200206if (this.concurrency === 'bench') {
201-values = await this.#mapTasksConcurrently(task => task.run())
207+const taskPromises = []
208+for (const task of this.#tasks.values()) {
209+taskPromises.push(task.run())
210+}
211+values = await Promise.all(taskPromises)
202212} else {
203213for (const task of this.#tasks.values()) {
204214values.push(await task.run())
205215}
206216}
217+207218this.dispatchEvent(new BenchEvent('complete'))
208219return values
209220}
@@ -240,39 +251,18 @@ export class Bench extends EventTarget {
240251return this.tasks.map(convert)
241252}
242253243-/**
244- * Applies a worker function to all registered tasks using the concurrency limit.
245- *
246- * Scheduling is handled via p-limit with the current threshold. The returned array preserves
247- * the iteration order of the tasks. If any scheduled worker function rejects, the returned promise
248- * rejects with the first error after the scheduled worker functions settle, as per Promise.all semantics.
249- *
250- * Notes:
251- * - Concurrency is controlled by Bench.threshold (Infinity means unlimited).
252- * - No measurements are performed here; measurements happen inside Task.
253- * - Used internally by run() and warmupTasks() when concurrency === 'bench'.
254- * @template R The resolved type produced by the worker function for each task.
255- * @param workerFn A function invoked for each Task; it must return a Promise<R>.
256- * @returns Promise that resolves to an array of results in the same order as task iteration.
257- */
258-async #mapTasksConcurrently<R>(
259-workerFn: (task: Task) => Promise<R>
260-): Promise<R[]> {
261-const limit = pLimit(Math.max(1, Math.floor(this.threshold)))
262-const promises: Promise<R>[] = []
263-for (const task of this.#tasks.values()) {
264-promises.push(limit(() => workerFn(task)))
265-}
266-return Promise.all(promises)
267-}
268-269254/**
270255 * warmup the benchmark tasks.
271256 */
272257async #warmupTasks (): Promise<void> {
273258this.dispatchEvent(new BenchEvent('warmup'))
259+274260if (this.concurrency === 'bench') {
275-await this.#mapTasksConcurrently(task => task.warmup())
261+const taskPromises = []
262+for (const task of this.#tasks.values()) {
263+taskPromises.push(task.warmup())
264+}
265+await Promise.all(taskPromises)
276266} else {
277267for (const task of this.#tasks.values()) {
278268await task.warmup()