chore(testing/bench): remove deprecated APIs (#2714)

This commit is contained in:
Asher Gomez 2022-09-30 01:27:10 +10:00 committed by GitHub
parent 4984358b15
commit 40d0466e46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 4 additions and 941 deletions

View File

@ -1,5 +1,4 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { bench, runBenchmarks } from "../testing/bench.ts";
import { equals32Bit, equalsNaive } from "./equals.ts"; import { equals32Bit, equalsNaive } from "./equals.ts";
console.log("generating benchmarks..."); console.log("generating benchmarks...");
@ -17,26 +16,20 @@ for (let i = 0; i < nCases; i++) {
testCases.push([arr1, arr3]); testCases.push([arr1, arr3]);
} }
bench({ Deno.bench({
name: "bench old equals", name: "bench old equals",
func(b) { fn() {
b.start();
for (const [a, b] of testCases) { for (const [a, b] of testCases) {
equalsNaive(a, b); equalsNaive(a, b);
} }
b.stop();
}, },
}); });
bench({ Deno.bench({
name: "bench simd equals", name: "bench simd equals",
func(b) { fn() {
b.start();
for (const [a, b] of testCases) { for (const [a, b] of testCases) {
equals32Bit(a, b); equals32Bit(a, b);
} }
b.stop();
}, },
}); });
runBenchmarks();

View File

@ -316,133 +316,6 @@ be reviewed along side the code changes that caused them, and ensures that when
others pull your changes, their tests will pass without needing to update others pull your changes, their tests will pass without needing to update
snapshots locally. snapshots locally.
## Benching
These APIs are deprecated. Use Deno.bench() instead. See
https://doc.deno.land/deno/unstable/~/Deno.bench for more details.
### Basic usage:
Benchmarks can be registered using the `bench` function, where you can define a
code, that should be benchmarked. `b.start()` has to be called at the start of
the part you want to benchmark and `b.stop()` at the end of it, otherwise an
error will be thrown.
After that simply calling `runBenchmarks()` will benchmark all registered
benchmarks and log the results in the commandline.
```ts
import {
bench,
runBenchmarks,
} from "https://deno.land/std@$STD_VERSION/testing/bench.ts";
bench(function forIncrementX1e9(b): void {
b.start();
for (let i = 0; i < 1e9; i++);
b.stop();
});
runBenchmarks();
```
Averaging execution time over multiple runs:
```ts
import { bench } from "https://deno.land/std@$STD_VERSION/testing/bench.ts";
bench({
name: "runs100ForIncrementX1e6",
runs: 100,
func(b): void {
b.start();
for (let i = 0; i < 1e6; i++);
b.stop();
},
});
```
Running specific benchmarks using regular expressions:
```ts
import {
runBenchmarks,
} from "https://deno.land/std@$STD_VERSION/testing/bench.ts";
runBenchmarks({ only: /desired/, skip: /exceptions/ });
```
### Processing benchmark results
`runBenchmarks()` returns a `Promise<BenchmarkRunResult>`, so you can process
the benchmarking results yourself. It contains detailed results of each
benchmark's run as `BenchmarkResult` s.
```ts
import {
BenchmarkRunResult,
runBenchmarks,
} from "https://deno.land/std@$STD_VERSION/testing/bench.ts";
runBenchmarks()
.then((results: BenchmarkRunResult) => {
console.log(results);
})
.catch((error: Error) => {
// ... errors if benchmark was badly constructed.
});
```
### Processing benchmarking progress
`runBenchmarks()` accepts an optional progress handler callback function, so you
can get information on the progress of the running benchmarking.
Using `{ silent: true }` means you wont see the default progression logs in the
commandline.
```ts
import {
BenchmarkRunProgress,
ProgressState,
runBenchmarks,
} from "https://deno.land/std@$STD_VERSION/testing/bench.ts";
runBenchmarks({ silent: true }, (p: BenchmarkRunProgress) => {
// initial progress data.
if (p.state === ProgressState.BenchmarkingStart) {
console.log(
`Starting benchmarking. Queued: ${
p.queued!.length
}, filtered: ${p.filtered}`,
);
}
// ...
});
```
#### Benching API
These APIs are deprecated. Use Deno.bench() instead. See
https://doc.deno.land/deno/unstable/~/Deno.bench for more details.
##### `bench(benchmark: BenchmarkDefinition | BenchmarkFunction): void`
Registers a benchmark that will be run once `runBenchmarks` is called.
##### `runBenchmarks(opts?: BenchmarkRunOptions, progressCb?: (p: BenchmarkRunProgress) => void | Promise<void>): Promise<BenchmarkRunResult>`
Runs all registered benchmarks serially. Filtering can be applied by setting
`BenchmarkRunOptions.only` and/or `BenchmarkRunOptions.skip` to regular
expressions matching benchmark names. Default progression logs can be turned off
with the `BenchmarkRunOptions.silent` flag.
##### `clearBenchmarks(opts?: BenchmarkClearOptions): void`
Clears all registered benchmarks, so calling `runBenchmarks()` after it wont run
them. Filtering can be applied by setting `BenchmarkRunOptions.only` and/or
`BenchmarkRunOptions.skip` to regular expressions matching benchmark names.
## Behavior-driven development ## Behavior-driven development
With the `bdd.ts` module you can write your tests in a familiar format for With the `bdd.ts` module you can write your tests in a familiar format for

View File

@ -1,387 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
/**
* **Deprecated**. Use `Deno.bench()` instead.
*
* See: https://doc.deno.land/deno/unstable/~/Deno.bench for details.
*
* @deprecated (will be removed after 0.157.0) Use `Deno.bench()` instead.
* @module
*/
import { assert } from "../_util/assert.ts";
import { deepAssign } from "../_util/deep_assign.ts";
interface BenchmarkClock {
start: number;
stop: number;
for?: string;
}
/** Provides methods for starting and stopping a benchmark clock. */
export interface BenchmarkTimer {
start: () => void;
stop: () => void;
}
/** Defines a benchmark through a named function. */
export interface BenchmarkFunction {
(b: BenchmarkTimer): void | Promise<void>;
name: string;
}
/** Defines a benchmark definition with configurable runs. */
export interface BenchmarkDefinition {
func: BenchmarkFunction;
name: string;
/** Defines how many times the provided `func` should be benchmarked in succession */
runs?: number;
}
/** Defines runBenchmark's run constraints by matching benchmark names. */
export interface BenchmarkRunOptions {
/** Only benchmarks which name match this regexp will be run*/
only?: RegExp;
/** Benchmarks which name match this regexp will be skipped */
skip?: RegExp;
/** Setting it to true prevents default benchmarking progress logs to the commandline*/
silent?: boolean;
}
/** Defines clearBenchmark's constraints by matching benchmark names. */
export interface BenchmarkClearOptions {
/** Only benchmarks which name match this regexp will be removed */
only?: RegExp;
/** Benchmarks which name match this regexp will be kept */
skip?: RegExp;
}
/** Defines the result of a single benchmark */
export interface BenchmarkResult {
/** The name of the benchmark */
name: string;
/** The total time it took to run a given benchmark */
totalMs: number;
/** Times the benchmark was run in succession. */
runsCount: number;
/** The average time of running the benchmark in milliseconds. */
measuredRunsAvgMs: number;
/** The individual measurements in milliseconds it took to run the benchmark.*/
measuredRunsMs: number[];
}
/** Defines the result of a `runBenchmarks` call */
export interface BenchmarkRunResult {
/** How many benchmark were ignored by the provided `only` and `skip` */
filtered: number;
/** The individual results for each benchmark that was run */
results: BenchmarkResult[];
}
/** Defines the current progress during the run of `runBenchmarks` */
export interface BenchmarkRunProgress extends BenchmarkRunResult {
/** List of the queued benchmarks to run with their name and their run count */
queued?: Array<{ name: string; runsCount: number }>;
/** The currently running benchmark with its name, run count and the already finished measurements in milliseconds */
running?: { name: string; runsCount: number; measuredRunsMs: number[] };
/** Indicates in which state benchmarking currently is */
state?: ProgressState;
}
/** Defines the states `BenchmarkRunProgress` can be in */
export enum ProgressState {
BenchmarkingStart = "benchmarking_start",
BenchStart = "bench_start",
BenchPartialResult = "bench_partial_result",
BenchResult = "bench_result",
BenchmarkingEnd = "benchmarking_end",
}
export class BenchmarkRunError extends Error {
benchmarkName?: string;
constructor(msg: string, benchmarkName?: string) {
super(msg);
this.name = "BenchmarkRunError";
this.benchmarkName = benchmarkName;
}
}
function red(text: string): string {
return Deno.noColor ? text : `\x1b[31m${text}\x1b[0m`;
}
function blue(text: string): string {
return Deno.noColor ? text : `\x1b[34m${text}\x1b[0m`;
}
function verifyOr1Run(runs?: number): number {
return runs && runs >= 1 && runs !== Infinity ? Math.floor(runs) : 1;
}
function assertTiming(clock: BenchmarkClock) {
// NaN indicates that a benchmark has not been timed properly
if (!clock.stop) {
throw new BenchmarkRunError(
`Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's stop method must be called`,
clock.for,
);
} else if (!clock.start) {
throw new BenchmarkRunError(
`Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's start method must be called`,
clock.for,
);
} else if (clock.start > clock.stop) {
throw new BenchmarkRunError(
`Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's start method must be called before its stop method`,
clock.for,
);
}
}
function createBenchmarkTimer(clock: BenchmarkClock): BenchmarkTimer {
return {
start() {
clock.start = performance.now();
},
stop() {
if (isNaN(clock.start)) {
throw new BenchmarkRunError(
`Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's start method must be called before its stop method`,
clock.for,
);
}
clock.stop = performance.now();
},
};
}
const candidates: BenchmarkDefinition[] = [];
/**
* @deprecated (will be removed after 0.157.0) Use `Deno.bench()` instead. See https://doc.deno.land/deno/unstable/~/Deno.bench
* for details.
*
* Registers a benchmark as a candidate for the runBenchmarks executor. */
export function bench(
benchmark: BenchmarkDefinition | BenchmarkFunction,
) {
if (!benchmark.name) {
throw new Error("The benchmark function must not be anonymous");
}
if (typeof benchmark === "function") {
candidates.push({ name: benchmark.name, runs: 1, func: benchmark });
} else {
candidates.push({
name: benchmark.name,
runs: verifyOr1Run(benchmark.runs),
func: benchmark.func,
});
}
}
/**
* Clears benchmark candidates which name matches `only` and doesn't match `skip`.
* Removes all candidates if options were not provided.
*
* @deprecated (will be removed after 0.157.0) Use `Deno.bench()` instead. See: https://doc.deno.land/deno/unstable/~/Deno.bench
* for details.
*/
export function clearBenchmarks({
only = /[^\s]/,
skip = /$^/,
}: BenchmarkClearOptions = {}) {
const keep = candidates.filter(
({ name }): boolean => !only.test(name) || skip.test(name),
);
candidates.splice(0, candidates.length);
candidates.push(...keep);
}
/**
* @deprecated (will be removed after 0.157.0) Use `Deno.bench()` instead. See https://doc.deno.land/deno/unstable/~/Deno.bench
* for details.
*
* Runs all registered and non-skipped benchmarks serially.
*
* @param [progressCb] provides the possibility to get updates of the current progress during the run of the benchmarking
* @returns results of the benchmarking
*/
export async function runBenchmarks(
{ only = /[^\s]/, skip = /^\s*$/, silent }: BenchmarkRunOptions = {},
progressCb?: (progress: BenchmarkRunProgress) => void | Promise<void>,
): Promise<BenchmarkRunResult> {
// Filtering candidates by the "only" and "skip" constraint
const benchmarks: BenchmarkDefinition[] = candidates.filter(
({ name }): boolean => only.test(name) && !skip.test(name),
);
// Init main counters and error flag
const filtered = candidates.length - benchmarks.length;
let failError: Error | undefined = undefined;
// Setting up a shared benchmark clock and timer
const clock: BenchmarkClock = { start: NaN, stop: NaN };
const b = createBenchmarkTimer(clock);
// Init progress data
const progress: BenchmarkRunProgress = {
// bench.run is already ensured with verifyOr1Run on register
queued: benchmarks.map((bench) => ({
name: bench.name,
runsCount: bench.runs!,
})),
results: [],
filtered,
state: ProgressState.BenchmarkingStart,
};
// Publish initial progress data
await publishProgress(progress, ProgressState.BenchmarkingStart, progressCb);
if (!silent) {
console.log(
"running",
benchmarks.length,
`benchmark${benchmarks.length === 1 ? " ..." : "s ..."}`,
);
}
// Iterating given benchmark definitions (await-in-loop)
for (const { name, runs = 0, func } of benchmarks) {
if (!silent) {
// See https://github.com/denoland/deno/pull/1452 about groupCollapsed
console.groupCollapsed(`benchmark ${name} ... `);
}
// Provide the benchmark name for clock assertions
clock.for = name;
// Remove benchmark from queued
assert(progress.queued);
const queueIndex = progress.queued.findIndex(
(queued) => queued.name === name && queued.runsCount === runs,
);
if (queueIndex != -1) {
progress.queued.splice(queueIndex, 1);
}
// Init the progress of the running benchmark
progress.running = { name, runsCount: runs, measuredRunsMs: [] };
// Publish starting of a benchmark
await publishProgress(progress, ProgressState.BenchStart, progressCb);
// Trying benchmark.func
let result = "";
try {
// Averaging runs
let pendingRuns = runs;
let totalMs = 0;
// Would be better 2 not run these serially
while (true) {
// b is a benchmark timer interfacing an unset (NaN) benchmark clock
await func(b);
// Making sure the benchmark was started/stopped properly
assertTiming(clock);
// Calculate length of run
const measuredMs = clock.stop - clock.start;
// Summing up
totalMs += measuredMs;
// Adding partial result
progress.running.measuredRunsMs.push(measuredMs);
// Publish partial benchmark results
await publishProgress(
progress,
ProgressState.BenchPartialResult,
progressCb,
);
// Resetting the benchmark clock
clock.start = clock.stop = NaN;
// Once all ran
if (!--pendingRuns) {
result = runs == 1
? `${totalMs}ms`
: `${runs} runs avg: ${totalMs / runs}ms`;
// Adding results
progress.results.push({
name,
totalMs,
runsCount: runs,
measuredRunsAvgMs: totalMs / runs,
measuredRunsMs: progress.running.measuredRunsMs,
});
// Clear currently running
delete progress.running;
// Publish results of the benchmark
await publishProgress(
progress,
ProgressState.BenchResult,
progressCb,
);
break;
}
}
} catch (err) {
if (err instanceof Error) {
failError = err;
if (!silent) {
console.groupEnd();
console.error(red(err.stack ?? ""));
}
}
break;
}
if (!silent) {
// Reporting
console.log(blue(result));
console.groupEnd();
}
// Resetting the benchmark clock
clock.start = clock.stop = NaN;
delete clock.for;
}
// Indicate finished running
delete progress.queued;
// Publish final result in Cb too
await publishProgress(progress, ProgressState.BenchmarkingEnd, progressCb);
if (!silent) {
// Closing results
console.log(
`benchmark result: ${failError ? red("FAIL") : blue("DONE")}. ` +
`${progress.results.length} measured; ${filtered} filtered`,
);
}
// Throw error if there was a failing benchmark
if (failError) {
throw failError;
}
const benchmarkRunResult = {
filtered,
results: progress.results,
};
return benchmarkRunResult;
}
async function publishProgress(
progress: BenchmarkRunProgress,
state: ProgressState,
progressCb?: (progress: BenchmarkRunProgress) => void | Promise<void>,
) {
progressCb && (await progressCb(cloneProgressWithState(progress, state)));
}
function cloneProgressWithState(
progress: BenchmarkRunProgress,
state: ProgressState,
): BenchmarkRunProgress {
return deepAssign({}, progress, { state }) as BenchmarkRunProgress;
}

View File

@ -1,37 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
/** **Deprecated**. Use `Deno.bench()` instead.
*
* @module
*/
import { bench, BenchmarkTimer, runBenchmarks } from "./bench.ts";
// Basic
bench(function forIncrementX1e9(b: BenchmarkTimer) {
b.start();
for (let i = 0; i < 1e9; i++);
b.stop();
});
// Reporting average measured time for $runs runs of func
bench({
name: "runs100ForIncrementX1e6",
runs: 100,
func(b) {
b.start();
for (let i = 0; i < 1e6; i++);
b.stop();
},
});
// Itsabug
bench(function throwing(b) {
b.start();
// Throws bc the timer's stop method is never called
});
// Bench control
if (import.meta.main) {
runBenchmarks({ skip: /throw/ });
}

View File

@ -1,379 +0,0 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import {
bench,
BenchmarkRunError,
BenchmarkRunProgress,
clearBenchmarks,
ProgressState,
runBenchmarks,
} from "./bench.ts";
import {
assert,
assertEquals,
assertRejects,
assertThrows,
} from "./asserts.ts";
Deno.test({
name: "benching",
fn: async function () {
bench(function forIncrementX1e3(b) {
b.start();
for (let i = 0; i < 1e3; i++);
b.stop();
});
bench(function forDecrementX1e3(b) {
b.start();
for (let i = 1e3; i > 0; i--);
b.stop();
});
bench(async function forAwaitFetchDenolandX10(b) {
b.start();
for (let i = 0; i < 10; i++) {
const r = await fetch("https://deno.land/");
await r.text();
}
b.stop();
});
bench(async function promiseAllFetchDenolandX10(b) {
const urls = Array.from({ length: 10 }, () => "https://deno.land/");
b.start();
await Promise.all(
urls.map(
async (denoland: string) => {
const r = await fetch(denoland);
await r.text();
},
),
);
b.stop();
});
bench({
name: "runs100ForIncrementX1e6",
runs: 100,
func(b) {
b.start();
for (let i = 0; i < 1e6; i++);
b.stop();
},
});
bench(function throwing(b) {
b.start();
// Throws bc the timer's stop method is never called
});
const benchResult = await runBenchmarks({ skip: /throw/ });
assertEquals(benchResult.filtered, 1);
assertEquals(benchResult.results.length, 5);
const resultWithSingleRunsFiltered = benchResult.results.filter(
({ name }) => name === "forDecrementX1e3",
);
assertEquals(resultWithSingleRunsFiltered.length, 1);
const resultWithSingleRuns = resultWithSingleRunsFiltered[0];
assert(!!resultWithSingleRuns.runsCount);
assert(!!resultWithSingleRuns.measuredRunsAvgMs);
assert(!!resultWithSingleRuns.measuredRunsMs);
assertEquals(resultWithSingleRuns.runsCount, 1);
assertEquals(resultWithSingleRuns.measuredRunsMs.length, 1);
const resultWithMultipleRunsFiltered = benchResult.results.filter(
({ name }) => name === "runs100ForIncrementX1e6",
);
assertEquals(resultWithMultipleRunsFiltered.length, 1);
const resultWithMultipleRuns = resultWithMultipleRunsFiltered[0];
assert(!!resultWithMultipleRuns.runsCount);
assert(!!resultWithMultipleRuns.measuredRunsAvgMs);
assert(!!resultWithMultipleRuns.measuredRunsMs);
assertEquals(resultWithMultipleRuns.runsCount, 100);
assertEquals(resultWithMultipleRuns.measuredRunsMs.length, 100);
clearBenchmarks();
},
});
Deno.test({
name: "Bench without name should throw",
fn() {
assertThrows(
() => {
bench(() => {});
},
Error,
"The benchmark function must not be anonymous",
);
},
});
Deno.test({
name: "Bench without stop should throw",
fn: async function () {
await assertRejects(
async () => {
bench(function benchWithoutStop(b) {
b.start();
// Throws bc the timer's stop method is never called
});
await runBenchmarks({ only: /benchWithoutStop/, silent: true });
},
BenchmarkRunError,
"The benchmark timer's stop method must be called",
);
},
});
Deno.test({
name: "Bench without start should throw",
fn: async function () {
await assertRejects(
async () => {
bench(function benchWithoutStart(b) {
b.stop();
// Throws bc the timer's start method is never called
});
await runBenchmarks({ only: /benchWithoutStart/, silent: true });
},
BenchmarkRunError,
"The benchmark timer's start method must be called",
);
},
});
Deno.test({
name: "Bench with stop before start should throw",
fn: async function () {
await assertRejects(
async () => {
bench(function benchStopBeforeStart(b) {
b.stop();
b.start();
// Throws bc the timer's stop is called before start
});
await runBenchmarks({ only: /benchStopBeforeStart/, silent: true });
},
BenchmarkRunError,
"The benchmark timer's start method must be called before its stop method",
);
},
});
Deno.test({
name: "clearBenchmarks should clear all candidates",
fn: async function () {
dummyBench("test");
clearBenchmarks();
const benchingResults = await runBenchmarks({ silent: true });
assertEquals(benchingResults.filtered, 0);
assertEquals(benchingResults.results.length, 0);
},
});
Deno.test({
name: "clearBenchmarks with only as option",
fn: async function () {
// to reset candidates
clearBenchmarks();
dummyBench("test");
dummyBench("onlyclear");
clearBenchmarks({ only: /only/ });
const benchingResults = await runBenchmarks({ silent: true });
assertEquals(benchingResults.filtered, 0);
assertEquals(benchingResults.results.length, 1);
assertEquals(benchingResults.results[0].name, "test");
},
});
Deno.test({
name: "clearBenchmarks with skip as option",
fn: async function () {
// to reset candidates
clearBenchmarks();
dummyBench("test");
dummyBench("skipclear");
clearBenchmarks({ skip: /skip/ });
const benchingResults = await runBenchmarks({ silent: true });
assertEquals(benchingResults.filtered, 0);
assertEquals(benchingResults.results.length, 1);
assertEquals(benchingResults.results[0].name, "skipclear");
},
});
Deno.test({
name: "clearBenchmarks with only and skip as option",
fn: async function () {
// to reset candidates
clearBenchmarks();
dummyBench("test");
dummyBench("clearonly");
dummyBench("clearskip");
dummyBench("clearonly");
clearBenchmarks({ only: /clear/, skip: /skip/ });
const benchingResults = await runBenchmarks({ silent: true });
assertEquals(benchingResults.filtered, 0);
assertEquals(benchingResults.results.length, 2);
assert(!!benchingResults.results.find(({ name }) => name === "test"));
assert(!!benchingResults.results.find(({ name }) => name === "clearskip"));
},
});
Deno.test({
name: "progressCallback of runBenchmarks",
fn: async function () {
clearBenchmarks();
dummyBench("skip");
dummyBench("single");
dummyBench("multiple", 2);
const progressCallbacks: BenchmarkRunProgress[] = [];
const benchingResults = await runBenchmarks(
{ skip: /skip/, silent: true },
(progress) => {
progressCallbacks.push(progress);
},
);
let pc = 0;
// Assert initial progress before running
let progress = progressCallbacks[pc++];
assert(progress.queued);
assertEquals(progress.state, ProgressState.BenchmarkingStart);
assertEquals(progress.filtered, 1);
assertEquals(progress.queued.length, 2);
assertEquals(progress.running, undefined);
assertEquals(progress.results, []);
// Assert start of bench "single"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchStart);
assertEquals(progress.filtered, 1);
assert(progress.queued);
assertEquals(progress.queued.length, 1);
assert(!!progress.queued.find(({ name }) => name == "multiple"));
assertEquals(progress.running, {
name: "single",
runsCount: 1,
measuredRunsMs: [],
});
assertEquals(progress.results, []);
// Assert running result of bench "single"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchPartialResult);
assert(progress.queued);
assertEquals(progress.queued.length, 1);
assertEquals(progress.running!.measuredRunsMs.length, 1);
assertEquals(progress.results.length, 0);
// Assert result of bench "single"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchResult);
assert(progress.queued);
assertEquals(progress.queued.length, 1);
assertEquals(progress.running, undefined);
assertEquals(progress.results.length, 1);
assert(!!progress.results.find(({ name }) => name == "single"));
// Assert start of bench "multiple"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchStart);
assert(progress.queued);
assertEquals(progress.queued.length, 0);
assertEquals(progress.running, {
name: "multiple",
runsCount: 2,
measuredRunsMs: [],
});
assertEquals(progress.results.length, 1);
// Assert first result of bench "multiple"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchPartialResult);
assert(progress.queued);
assertEquals(progress.queued.length, 0);
assertEquals(progress.running!.measuredRunsMs.length, 1);
assertEquals(progress.results.length, 1);
// Assert second result of bench "multiple"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchPartialResult);
assert(progress.queued);
assertEquals(progress.queued.length, 0);
assertEquals(progress.running!.measuredRunsMs.length, 2);
assertEquals(progress.results.length, 1);
// Assert finish of bench "multiple"
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchResult);
assert(progress.queued);
assertEquals(progress.queued.length, 0);
assertEquals(progress.running, undefined);
assertEquals(progress.results.length, 2);
assert(!!progress.results.find(({ name }) => name == "single"));
const resultOfMultiple = progress.results.filter(
({ name }) => name == "multiple",
);
assertEquals(resultOfMultiple.length, 1);
assert(!!resultOfMultiple[0].measuredRunsMs);
assert(!isNaN(resultOfMultiple[0].measuredRunsAvgMs));
assertEquals(resultOfMultiple[0].measuredRunsMs.length, 2);
// The last progress should equal the final result from promise except the state property
progress = progressCallbacks[pc++];
assertEquals(progress.state, ProgressState.BenchmarkingEnd);
delete progress.state;
assertEquals(progress, benchingResults);
},
});
Deno.test({
name: "async progressCallback",
fn: async function () {
clearBenchmarks();
dummyBench("single");
const asyncCallbacks = [];
await runBenchmarks({ silent: true }, (progress) => {
return new Promise((resolve) => {
queueMicrotask(() => {
asyncCallbacks.push(progress);
resolve();
});
});
});
assertEquals(asyncCallbacks.length, 5);
},
});
function dummyBench(name: string, runs = 1) {
bench({
name,
runs,
func(b) {
b.start();
b.stop();
},
});
}