summaryrefslogtreecommitdiff
path: root/cli/js
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2023-09-19 12:10:20 +0200
committerGitHub <noreply@github.com>2023-09-19 12:10:20 +0200
commit2772d302f57cfdce09c7ba2df8a887d28eba8b9a (patch)
tree776abace72c8b8c334a3f73f4f8f1b521b3c6863 /cli/js
parentb9b4ad31d991bdbc50ddaea8d423a5d285d5f317 (diff)
perf: make `deno test` 10x faster (#20550)
Diffstat (limited to 'cli/js')
-rw-r--r--cli/js/40_testing.js120
1 files changed, 60 insertions, 60 deletions
diff --git a/cli/js/40_testing.js b/cli/js/40_testing.js
index 30905fb54..2702dccf1 100644
--- a/cli/js/40_testing.js
+++ b/cli/js/40_testing.js
@@ -22,7 +22,6 @@ const {
MapPrototypeSet,
MathCeil,
ObjectKeys,
- ObjectHasOwn,
ObjectPrototypeIsPrototypeOf,
Promise,
SafeArrayIterator,
@@ -151,26 +150,14 @@ const OP_DETAILS = {
"op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
};
-function collectReliableOpMetrics() {
- let metrics = core.metrics();
- if (metrics.opsDispatched > metrics.opsCompleted) {
- // If there are still async ops pending, we drain the event loop to the
- // point where all ops that can return `Poll::Ready` have done so, to ensure
- // that any ops are ready because of user cleanup code are completed.
- const hasPendingWorkerOps = metrics.ops.op_host_recv_message && (
- metrics.ops.op_host_recv_message.opsDispatched >
- metrics.ops.op_host_recv_message.opsCompleted ||
- metrics.ops.op_host_recv_ctrl.opsDispatched >
- metrics.ops.op_host_recv_ctrl.opsCompleted
- );
- return opSanitizerDelay(hasPendingWorkerOps).then(() => {
- metrics = core.metrics();
- const traces = new Map(core.opCallTraces);
- return { metrics, traces };
- });
- }
- const traces = new Map(core.opCallTraces);
- return { metrics, traces };
+let opIdHostRecvMessage = -1;
+let opIdHostRecvCtrl = -1;
+let opNames = null;
+
+function populateOpNames() {
+ opNames = core.ops.op_op_names();
+ opIdHostRecvMessage = opNames.indexOf("op_host_recv_message");
+ opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl");
}
// Wrap test function in additional assertion that makes sure
@@ -181,50 +168,61 @@ function collectReliableOpMetrics() {
function assertOps(fn) {
/** @param desc {TestDescription | TestStepDescription} */
return async function asyncOpSanitizer(desc) {
- let metrics = collectReliableOpMetrics();
- if (metrics.then) {
- // We're delaying so await to get the result asynchronously.
- metrics = await metrics;
+ if (opNames === null) populateOpNames();
+ const res = core.ops.op_test_op_sanitizer_collect(
+ desc.id,
+ false,
+ opIdHostRecvMessage,
+ opIdHostRecvCtrl,
+ );
+ if (res !== 0) {
+ await opSanitizerDelay(res === 2);
+ core.ops.op_test_op_sanitizer_collect(
+ desc.id,
+ true,
+ opIdHostRecvMessage,
+ opIdHostRecvCtrl,
+ );
}
- const { metrics: pre, traces: preTraces } = metrics;
- let post;
+ const preTraces = new Map(core.opCallTraces);
let postTraces;
+ let report = null;
try {
const innerResult = await fn(desc);
if (innerResult) return innerResult;
} finally {
- let metrics = collectReliableOpMetrics();
- if (metrics.then) {
- // We're delaying so await to get the result asynchronously.
- metrics = await metrics;
+ let res = core.ops.op_test_op_sanitizer_finish(
+ desc.id,
+ false,
+ opIdHostRecvMessage,
+ opIdHostRecvCtrl,
+ );
+ if (res === 1 || res === 2) {
+ await opSanitizerDelay(res === 2);
+ res = core.ops.op_test_op_sanitizer_finish(
+ desc.id,
+ true,
+ opIdHostRecvMessage,
+ opIdHostRecvCtrl,
+ );
+ }
+ postTraces = new Map(core.opCallTraces);
+ if (res === 3) {
+ report = core.ops.op_test_op_sanitizer_report(desc.id);
}
- ({ metrics: post, traces: postTraces } = metrics);
}
- // We're checking diff because one might spawn HTTP server in the background
- // that will be a pending async op before test starts.
- const dispatchedDiff = post.opsDispatchedAsync - pre.opsDispatchedAsync;
- const completedDiff = post.opsCompletedAsync - pre.opsCompletedAsync;
-
- if (dispatchedDiff === completedDiff) return null;
+ if (report === null) return null;
const details = [];
- for (const key in post.ops) {
- if (!ObjectHasOwn(post.ops, key)) {
- continue;
- }
- const preOp = pre.ops[key] ??
- { opsDispatchedAsync: 0, opsCompletedAsync: 0 };
- const postOp = post.ops[key];
- const dispatchedDiff = postOp.opsDispatchedAsync -
- preOp.opsDispatchedAsync;
- const completedDiff = postOp.opsCompletedAsync -
- preOp.opsCompletedAsync;
-
- if (dispatchedDiff > completedDiff) {
- const [name, hint] = OP_DETAILS[key] || [key, null];
- const count = dispatchedDiff - completedDiff;
+ for (const opReport of report) {
+ const opName = opNames[opReport.id];
+ const diff = opReport.diff;
+
+ if (diff > 0) {
+ const [name, hint] = OP_DETAILS[opName] || [opName, null];
+ const count = diff;
let message = `${count} async operation${
count === 1 ? "" : "s"
} to ${name} ${
@@ -234,8 +232,8 @@ function assertOps(fn) {
message += ` This is often caused by not ${hint}.`;
}
const traces = [];
- for (const [id, { opName, stack }] of postTraces) {
- if (opName !== key) continue;
+ for (const [id, { opName: traceOpName, stack }] of postTraces) {
+ if (traceOpName !== opName) continue;
if (MapPrototypeHas(preTraces, id)) continue;
ArrayPrototypePush(traces, stack);
}
@@ -247,9 +245,9 @@ function assertOps(fn) {
message += ArrayPrototypeJoin(traces, "\n\n");
}
ArrayPrototypePush(details, message);
- } else if (dispatchedDiff < completedDiff) {
- const [name, hint] = OP_DETAILS[key] || [key, null];
- const count = completedDiff - dispatchedDiff;
+ } else if (diff < 0) {
+ const [name, hint] = OP_DETAILS[opName] || [opName, null];
+ const count = -diff;
let message = `${count} async operation${
count === 1 ? "" : "s"
} to ${name} ${
@@ -261,8 +259,8 @@ function assertOps(fn) {
message += ` This is often caused by not ${hint}.`;
}
const traces = [];
- for (const [id, { opName, stack }] of preTraces) {
- if (opName !== key) continue;
+ for (const [id, { opName: traceOpName, stack }] of preTraces) {
+ if (opName !== traceOpName) continue;
if (MapPrototypeHas(postTraces, id)) continue;
ArrayPrototypePush(traces, stack);
}
@@ -274,6 +272,8 @@ function assertOps(fn) {
message += ArrayPrototypeJoin(traces, "\n\n");
}
ArrayPrototypePush(details, message);
+ } else {
+ throw new Error("unreachable");
}
}