summaryrefslogtreecommitdiff
path: root/runtime/js/40_testing.js
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/js/40_testing.js')
-rw-r--r--runtime/js/40_testing.js197
1 files changed, 78 insertions, 119 deletions
diff --git a/runtime/js/40_testing.js b/runtime/js/40_testing.js
index 47af45110..8c7d69fb0 100644
--- a/runtime/js/40_testing.js
+++ b/runtime/js/40_testing.js
@@ -4,11 +4,10 @@
((window) => {
const core = window.Deno.core;
const { setExitHandler } = window.__bootstrap.os;
- const { Console, inspectArgs } = window.__bootstrap.console;
+ const { Console } = window.__bootstrap.console;
const { serializePermissions } = window.__bootstrap.permissions;
const { assert } = window.__bootstrap.infra;
const {
- AggregateErrorPrototype,
ArrayFrom,
ArrayPrototypeFilter,
ArrayPrototypeJoin,
@@ -537,8 +536,23 @@
};
}
+ /**
+ * @typedef {{
+ * id: number,
+ * name: string,
+ * fn: BenchFunction
+ * origin: string,
+ * filteredOut: boolean,
+ * ignore: boolean,
+ * only: boolean.
+ * sanitizeExit: boolean,
+ * permissions: PermissionOptions,
+ * }} BenchDescription
+ */
+
const tests = [];
- const benches = [];
+ /** @type {BenchDescription[]} */
+ const benchDescs = [];
// Main test function provided by Deno.
function test(
@@ -655,12 +669,11 @@
maybeFn,
) {
core.opSync("op_bench_check_unstable");
- let benchDef;
+ let benchDesc;
const defaults = {
ignore: false,
+ baseline: false,
only: false,
- sanitizeOps: true,
- sanitizeResources: true,
sanitizeExit: true,
permissions: null,
};
@@ -670,7 +683,7 @@
throw new TypeError("The bench name can't be empty");
}
if (typeof optionsOrFn === "function") {
- benchDef = { fn: optionsOrFn, name: nameOrFnOrOptions, ...defaults };
+ benchDesc = { fn: optionsOrFn, name: nameOrFnOrOptions, ...defaults };
} else {
if (!maybeFn || typeof maybeFn !== "function") {
throw new TypeError("Missing bench function");
@@ -685,7 +698,7 @@
"Unexpected 'name' field in options, bench name is already provided as the first argument.",
);
}
- benchDef = {
+ benchDesc = {
...defaults,
...optionsOrFn,
fn: maybeFn,
@@ -702,7 +715,7 @@
if (maybeFn != undefined) {
throw new TypeError("Unexpected third argument to Deno.bench()");
}
- benchDef = {
+ benchDesc = {
...defaults,
fn: nameOrFnOrOptions,
name: nameOrFnOrOptions.name,
@@ -732,28 +745,18 @@
if (!name) {
throw new TypeError("The bench name can't be empty");
}
- benchDef = { ...defaults, ...nameOrFnOrOptions, fn, name };
+ benchDesc = { ...defaults, ...nameOrFnOrOptions, fn, name };
}
+ benchDesc.origin = getBenchOrigin();
const AsyncFunction = (async () => {}).constructor;
- benchDef.async = AsyncFunction === benchDef.fn.constructor;
+ benchDesc.async = AsyncFunction === benchDesc.fn.constructor;
- ArrayPrototypePush(benches, benchDef);
- }
-
- function formatError(error) {
- if (ObjectPrototypeIsPrototypeOf(AggregateErrorPrototype, error)) {
- const message = error
- .errors
- .map((error) =>
- inspectArgs([error]).replace(/^(?!\s*$)/gm, " ".repeat(4))
- )
- .join("\n");
-
- return error.name + "\n" + message + error.stack;
- }
+ const { id, filteredOut } = core.opSync("op_register_bench", benchDesc);
+ benchDesc.id = id;
+ benchDesc.filteredOut = filteredOut;
- return inspectArgs([error]);
+ ArrayPrototypePush(benchDescs, benchDesc);
}
/**
@@ -848,7 +851,8 @@
};
}
- async function benchMeasure(timeBudget, fn, step, sync) {
+ async function benchMeasure(timeBudget, desc) {
+ const fn = desc.fn;
let n = 0;
let avg = 0;
let wavg = 0;
@@ -859,11 +863,10 @@
// warmup step
let c = 0;
- step.warmup = true;
let iterations = 20;
let budget = 10 * 1e6;
- if (sync) {
+ if (!desc.async) {
while (budget > 0 || iterations-- > 0) {
const t1 = benchNow();
@@ -890,13 +893,11 @@
wavg /= c;
// measure step
- step.warmup = false;
-
if (wavg > lowPrecisionThresholdInNs) {
let iterations = 10;
let budget = timeBudget * 1e6;
- if (sync) {
+ if (!desc.async) {
while (budget > 0 || iterations-- > 0) {
const t1 = benchNow();
@@ -906,7 +907,7 @@
n++;
avg += iterationTime;
budget -= iterationTime;
- all.push(iterationTime);
+ ArrayPrototypePush(all, iterationTime);
if (iterationTime < min) min = iterationTime;
if (iterationTime > max) max = iterationTime;
}
@@ -920,7 +921,7 @@
n++;
avg += iterationTime;
budget -= iterationTime;
- all.push(iterationTime);
+ ArrayPrototypePush(all, iterationTime);
if (iterationTime < min) min = iterationTime;
if (iterationTime > max) max = iterationTime;
}
@@ -929,7 +930,7 @@
let iterations = 10;
let budget = timeBudget * 1e6;
- if (sync) {
+ if (!desc.async) {
while (budget > 0 || iterations-- > 0) {
const t1 = benchNow();
for (let c = 0; c < lowPrecisionThresholdInNs; c++) fn();
@@ -937,7 +938,7 @@
n++;
avg += iterationTime;
- all.push(iterationTime);
+ ArrayPrototypePush(all, iterationTime);
if (iterationTime < min) min = iterationTime;
if (iterationTime > max) max = iterationTime;
budget -= iterationTime * lowPrecisionThresholdInNs;
@@ -962,21 +963,15 @@
return benchStats(n, wavg > lowPrecisionThresholdInNs, avg, min, max, all);
}
- async function runBench(bench) {
- const step = new BenchStep({
- name: bench.name,
- sanitizeExit: bench.sanitizeExit,
- warmup: false,
- });
-
+ async function runBench(desc) {
let token = null;
try {
- if (bench.permissions) {
- token = pledgePermissions(bench.permissions);
+ if (desc.permissions) {
+ token = pledgePermissions(desc.permissions);
}
- if (bench.sanitizeExit) {
+ if (desc.sanitizeExit) {
setExitHandler((exitCode) => {
assert(
false,
@@ -986,24 +981,31 @@
}
const benchTimeInMs = 500;
- const fn = bench.fn.bind(null, step);
- const stats = await benchMeasure(benchTimeInMs, fn, step, !bench.async);
+ const stats = await benchMeasure(benchTimeInMs, desc);
- return { ok: { stats, ...bench } };
+ return { ok: stats };
} catch (error) {
- return { failed: { ...bench, error: formatError(error) } };
+ return { failed: core.destructureError(error) };
} finally {
if (bench.sanitizeExit) setExitHandler(null);
if (token !== null) restorePermissions(token);
}
}
+ let origin = null;
+
function getTestOrigin() {
- return core.opSync("op_get_test_origin");
+ if (origin == null) {
+ origin = core.opSync("op_get_test_origin");
+ }
+ return origin;
}
function getBenchOrigin() {
- return core.opSync("op_get_bench_origin");
+ if (origin == null) {
+ origin = core.opSync("op_get_bench_origin");
+ }
+ return origin;
}
function reportTestPlan(plan) {
@@ -1036,30 +1038,6 @@
});
}
- function reportBenchPlan(plan) {
- core.opSync("op_dispatch_bench_event", {
- plan,
- });
- }
-
- function reportBenchConsoleOutput(console) {
- core.opSync("op_dispatch_bench_event", {
- output: { console },
- });
- }
-
- function reportBenchWait(description) {
- core.opSync("op_dispatch_bench_event", {
- wait: description,
- });
- }
-
- function reportBenchResult(origin, result) {
- core.opSync("op_dispatch_bench_event", {
- result: [origin, result],
- });
- }
-
function benchNow() {
return core.opSync("op_bench_now");
}
@@ -1120,50 +1098,52 @@
}
}
- async function runBenchmarks({
- filter = null,
- } = {}) {
+ async function runBenchmarks() {
core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask);
const origin = getBenchOrigin();
const originalConsole = globalThis.console;
- globalThis.console = new Console(reportBenchConsoleOutput);
+ globalThis.console = new Console((s) => {
+ core.opSync("op_dispatch_bench_event", { output: s });
+ });
- const only = ArrayPrototypeFilter(benches, (bench) => bench.only);
+ const only = ArrayPrototypeFilter(benchDescs, (bench) => bench.only);
const filtered = ArrayPrototypeFilter(
- only.length > 0 ? only : benches,
- createTestFilter(filter),
+ only.length > 0 ? only : benchDescs,
+ (desc) => !desc.filteredOut && !desc.ignore,
);
let groups = new Set();
- const benchmarks = ArrayPrototypeFilter(filtered, (bench) => !bench.ignore);
-
// make sure ungrouped benchmarks are placed above grouped
groups.add(undefined);
- for (const bench of benchmarks) {
- bench.group ||= undefined;
- groups.add(bench.group);
+ for (const desc of filtered) {
+ desc.group ||= undefined;
+ groups.add(desc.group);
}
groups = ArrayFrom(groups);
ArrayPrototypeSort(
- benchmarks,
+ filtered,
(a, b) => groups.indexOf(a.group) - groups.indexOf(b.group),
);
- reportBenchPlan({
- origin,
- total: benchmarks.length,
- usedOnly: only.length > 0,
- names: ArrayPrototypeMap(benchmarks, (bench) => bench.name),
+ core.opSync("op_dispatch_bench_event", {
+ plan: {
+ origin,
+ total: filtered.length,
+ usedOnly: only.length > 0,
+ names: ArrayPrototypeMap(filtered, (desc) => desc.name),
+ },
});
- for (const bench of benchmarks) {
- bench.baseline = !!bench.baseline;
- reportBenchWait({ origin, ...bench });
- reportBenchResult(origin, await runBench(bench));
+ for (const desc of filtered) {
+ desc.baseline = !!desc.baseline;
+ core.opSync("op_dispatch_bench_event", { wait: desc.id });
+ core.opSync("op_dispatch_bench_event", {
+ result: [desc.id, await runBench(desc)],
+ });
}
globalThis.console = originalConsole;
@@ -1364,27 +1344,6 @@
}
}
- /**
- * @typedef {{
- * name: string;
- * sanitizeExit: boolean,
- * warmup: boolean,
- * }} BenchStepParams
- */
- class BenchStep {
- /** @type {BenchStepParams} */
- #params;
-
- /** @param params {BenchStepParams} */
- constructor(params) {
- this.#params = params;
- }
-
- get name() {
- return this.#params.name;
- }
- }
-
/** @param parentStep {TestStep} */
function createTestContext(parentStep) {
return {