diff options
author | Luca Casonato <hello@lcas.dev> | 2023-09-19 12:10:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-19 12:10:20 +0200 |
commit | 2772d302f57cfdce09c7ba2df8a887d28eba8b9a (patch) | |
tree | 776abace72c8b8c334a3f73f4f8f1b521b3c6863 /cli/js/40_testing.js | |
parent | b9b4ad31d991bdbc50ddaea8d423a5d285d5f317 (diff) |
perf: make `deno test` 10x faster (#20550)
Diffstat (limited to 'cli/js/40_testing.js')
-rw-r--r-- | cli/js/40_testing.js | 120 |
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"); } } |