From 99dc4cd8d2b0843699a78acb9a6dce2ddaa7c352 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Sun, 22 Oct 2023 13:53:29 +0200 Subject: [PATCH 1/3] use one Map for tasks and todos --- src/bench.ts | 14 ++++++-------- src/task.ts | 7 +++++++ src/types.ts | 5 +++++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/bench.ts b/src/bench.ts index 676b8ec..3dd9b1b 100644 --- a/src/bench.ts +++ b/src/bench.ts @@ -22,8 +22,6 @@ export default class Bench extends EventTarget { */ _tasks: Map = new Map(); - _todos: Map = new Map(); - signal?: AbortSignal; throws: boolean; @@ -108,7 +106,7 @@ export default class Bench extends EventTarget { * add a benchmark task to the task map */ add(name: string, fn: Fn, opts: FnOptions = {}) { - const task = new Task(this, name, fn, opts); + const task = new Task(this, name, fn, { ...opts, isTodo: false }); this._tasks.set(name, task); this.dispatchEvent(createBenchEvent('add', task)); return this; @@ -119,8 +117,8 @@ export default class Bench extends EventTarget { */ // eslint-disable-next-line @typescript-eslint/no-empty-function todo(name: string, fn: Fn = () => {}, opts: FnOptions = {}) { - const task = new Task(this, name, fn, opts); - this._todos.set(name, task); + const task = new Task(this, name, fn, { ...opts, isTodo: true }); + this._tasks.set(name, task); this.dispatchEvent(createBenchEvent('todo', task)); return this; } @@ -175,18 +173,18 @@ export default class Bench extends EventTarget { * (getter) tasks results as an array */ get results(): (TaskResult | undefined)[] { - return [...this._tasks.values()].map((task) => task.result); + return this.tasks.map((task) => task.result); } /** * (getter) tasks as an array */ get tasks(): Task[] { - return [...this._tasks.values()]; + return [...this._tasks.values()].filter((task) => !task.isTodo); } get todos(): Task[] { - return [...this._todos.values()]; + return [...this._tasks.values()].filter((task) => task.isTodo); } /** diff --git a/src/task.ts b/src/task.ts index da9d162..2db4dc6 100644 --- a/src/task.ts +++ b/src/task.ts @@ -42,12 +42,19 @@ export default class Task extends EventTarget { */ opts: FnOptions; + /** + * Indicate if the task a todo task + */ + isTodo: boolean; + constructor(bench: Bench, name: string, fn: Fn, opts: FnOptions = {}) { super(); this.bench = bench; this.name = name; this.fn = fn; this.opts = opts; + this.isTodo = opts.isTodo ?? false; + // TODO: support signals in Tasks } diff --git a/src/types.ts b/src/types.ts index 2e0bb75..d0cd03d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,11 @@ export interface FnOptions { * An optional function that is run after all iterations of this task end */ afterAll?: (this: Task) => void | Promise; + + /** + * Task is a todo + */ + isTodo?: boolean; } /** From 764e5fc47af50cda8f0c0047906f2ff82a895562 Mon Sep 17 00:00:00 2001 From: uzlopak Date: Mon, 23 Oct 2023 11:12:29 +0200 Subject: [PATCH 2/3] add ability to run only a specific task --- src/bench.ts | 31 +++++++++++++++++++++++++------ src/task.ts | 3 +++ src/utils.ts | 16 ++++++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/bench.ts b/src/bench.ts index 3dd9b1b..41977c3 100644 --- a/src/bench.ts +++ b/src/bench.ts @@ -10,7 +10,7 @@ import type { import { createBenchEvent } from './event'; import Task from './task'; import { AddEventListenerOptionsArgument, RemoveEventListenerOptionsArgument } from './types'; -import { now } from './utils'; +import { now, taskIdFromEnv } from './utils'; /** * The Benchmark instance for keeping track of the benchmark tasks and controlling @@ -20,7 +20,9 @@ export default class Bench extends EventTarget { /* * @private the task map */ - _tasks: Map = new Map(); + _tasks: Map = new Map(); + + _taskIdCounter = 0; signal?: AbortSignal; @@ -73,6 +75,17 @@ export default class Bench extends EventTarget { async run() { this.dispatchEvent(createBenchEvent('start')); const values: Task[] = []; + + const taskId = taskIdFromEnv(); + if (taskId !== -1) { + const task = this.getTask(taskId); + if (task) { + await task.run(); + return [task]; + } + return []; + } + for (const task of [...this._tasks.values()]) { if (this.signal?.aborted) values.push(task); else values.push(await task.run()); @@ -155,9 +168,10 @@ export default class Bench extends EventTarget { * table of the tasks results */ table() { - return this.tasks.map(({ name, result }) => { + return this.tasks.map(({ name, id, result }) => { if (result) { return { + TaskId: id, 'Task Name': name, 'ops/sec': result.error ? 'NaN' : parseInt(result.hz.toString(), 10).toLocaleString(), 'Average Time (ns)': result.error ? 'NaN' : result.mean * 1000 * 1000, @@ -188,9 +202,14 @@ export default class Bench extends EventTarget { } /** - * get a task based on the task name + * get a task based on the task name or task id */ - getTask(name: string): Task | undefined { - return this._tasks.get(name); + getTask(t: string | number): Task | undefined { + if (typeof t === 'string') { + return this._tasks.get(t); + } + return [...this._tasks.values()].filter( + (task) => task.id === t, + )[0]; } } diff --git a/src/task.ts b/src/task.ts index 2db4dc6..e4b3cb3 100644 --- a/src/task.ts +++ b/src/task.ts @@ -47,6 +47,8 @@ export default class Task extends EventTarget { */ isTodo: boolean; + id: number; + constructor(bench: Bench, name: string, fn: Fn, opts: FnOptions = {}) { super(); this.bench = bench; @@ -54,6 +56,7 @@ export default class Task extends EventTarget { this.fn = fn; this.opts = opts; this.isTodo = opts.isTodo ?? false; + this.id = bench._taskIdCounter++; // eslint-disable-line no-param-reassign // TODO: support signals in Tasks } diff --git a/src/utils.ts b/src/utils.ts index bc69a96..b3b9ea0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -69,3 +69,19 @@ export const isAsyncTask = async (task: Task) => { return false; } }; + +export const isNode = (() => process?.release.name === 'node')(); + +export const taskIdFromEnv = (): number => { + if ( + isNode + && process.env.TINYBENCH_TASK_ID + ) { + return parseInt(process.env.TINYBENCH_TASK_ID, 10); + } + return -1; +}; + +export const isESM = (() => typeof __dirname !== 'string')(); + +export const isCJS = !isESM; From 4b96cf126e57dad7b581f50d8fb07fa45ca3ab1c Mon Sep 17 00:00:00 2001 From: Vlad Sirenko Date: Tue, 31 Oct 2023 16:15:31 -0700 Subject: [PATCH 3/3] more flexible --- src/bench.ts | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/bench.ts b/src/bench.ts index 41977c3..a53391d 100644 --- a/src/bench.ts +++ b/src/bench.ts @@ -12,6 +12,8 @@ import Task from './task'; import { AddEventListenerOptionsArgument, RemoveEventListenerOptionsArgument } from './types'; import { now, taskIdFromEnv } from './utils'; +let benchIdCounter = 0; + /** * The Benchmark instance for keeping track of the benchmark tasks and controlling * them. @@ -20,7 +22,9 @@ export default class Bench extends EventTarget { /* * @private the task map */ - _tasks: Map = new Map(); + _tasks: Map = new Map(); + + _benchIdCounter = benchIdCounter++; _taskIdCounter = 0; @@ -78,12 +82,12 @@ export default class Bench extends EventTarget { const taskId = taskIdFromEnv(); if (taskId !== -1) { - const task = this.getTask(taskId); + const task = this.getTaskById(taskId); if (task) { - await task.run(); - return [task]; + values.push(await task.run()); } - return []; + this.dispatchEvent(createBenchEvent('complete')); + return values; } for (const task of [...this._tasks.values()]) { @@ -202,14 +206,18 @@ export default class Bench extends EventTarget { } /** - * get a task based on the task name or task id + * get a task based on the task name */ - getTask(t: string | number): Task | undefined { - if (typeof t === 'string') { - return this._tasks.get(t); - } - return [...this._tasks.values()].filter( + getTask(t: string): Task | undefined { + return this._tasks.get(t); + } + + /** + * get a task based on the task id + */ + getTaskById(t: number): Task | undefined { + return [...this._tasks.values()].find( (task) => task.id === t, - )[0]; + ); } }