mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
chore(testing/bench): remove deprecated APIs (#2714)
This commit is contained in:
parent
4984358b15
commit
40d0466e46
@ -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();
|
|
||||||
|
@ -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
|
||||||
|
387
testing/bench.ts
387
testing/bench.ts
@ -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;
|
|
||||||
}
|
|
@ -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/ });
|
|
||||||
}
|
|
@ -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();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user