Skip to content

Commit

Permalink
perf(ext/websocket): use opAsync2 to avoid spread deopt (denoland#18525)
Browse files Browse the repository at this point in the history
This commit adds a new core API `opAsync2` to call an async op with
atmost 2 arguments. Spread argument iterators has a pretty big perf hit
when calling ops.

| name | avg msg/sec/core |
| --- | --- |
| 1.32.1 | `127820.750000` |
| denoland#18506 | `140079.000000` |
| denoland#18506 + denoland#18509 | `150104.250000` |
| denoland#18506 + denoland#18509 + this | `157340.000000` |
  • Loading branch information
littledivy committed Mar 31, 2023
1 parent feab94f commit aa9b94a
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 18 deletions.
19 changes: 16 additions & 3 deletions core/01_core.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,24 @@
return res;
}

function rollPromiseId() {
return nextPromiseId++;
function opAsync2(name, arg0, arg1) {
const id = nextPromiseId++;
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
try {
ops[name](id, arg0, arg1);
} catch (err) {
// Cleanup the just-created promise
getPromise(id);
// Rethrow the error
throw err;
}
promise = handleOpCallTracing(name, id, promise);
promise[promiseIdSymbol] = id;
return promise;
}

function opAsync(name, ...args) {
const id = rollPromiseId();
const id = nextPromiseId++;
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
try {
ops[name](id, ...new SafeArrayIterator(args));
Expand Down Expand Up @@ -376,6 +388,7 @@
// Extra Deno.core.* exports
const core = ObjectAssign(globalThis.Deno.core, {
opAsync,
opAsync2,
resources,
metrics,
registerErrorBuilder,
Expand Down
4 changes: 2 additions & 2 deletions core/examples/http_bench_json_ops/http_bench_json_ops.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// then write this fixed 'responseBuf'. The point of this benchmark is to
// exercise the event loop in a simple yet semi-realistic way.

const { ops, opAsync } = Deno.core;
const { ops, opAsync, opAsync2 } = Deno.core;

const requestBuf = new Uint8Array(64 * 1024);
const responseBuf = new Uint8Array(
Expand All @@ -23,7 +23,7 @@ function accept(serverRid) {
}

function read(serverRid, buf) {
return opAsync("op_read_socket", serverRid, buf);
return opAsync2("op_read_socket", serverRid, buf);
}

async function serve(rid) {
Expand Down
2 changes: 1 addition & 1 deletion core/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2918,7 +2918,7 @@ pub mod tests {
r#"
let zero_copy_a = new Uint8Array([0]);
Deno.core.opAsync("op_test", null, zero_copy_a);
Deno.core.opAsync2("op_test", null, zero_copy_a);
"#,
)
.unwrap();
Expand Down
12 changes: 6 additions & 6 deletions ext/fs/30_fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function chmodSync(path, mode) {
}

async function chmod(path, mode) {
await core.opAsync("op_chmod_async", pathFromURL(path), mode);
await core.opAsync2("op_chmod_async", pathFromURL(path), mode);
}

function chownSync(
Expand Down Expand Up @@ -121,7 +121,7 @@ async function mkdir(
path,
options,
) {
await core.opAsync("op_mkdir_async", mkdirArgs(path, options));
await core.opAsync2("op_mkdir_async", mkdirArgs(path, options));
}

function readDirSync(path) {
Expand Down Expand Up @@ -349,15 +349,15 @@ function ftruncateSync(rid, len) {
}

async function ftruncate(rid, len) {
await core.opAsync("op_ftruncate_async", rid, coerceLen(len));
await core.opAsync2("op_ftruncate_async", rid, coerceLen(len));
}

function truncateSync(path, len) {
ops.op_truncate_sync(path, coerceLen(len));
}

async function truncate(path, len) {
await core.opAsync("op_truncate_async", path, coerceLen(len));
await core.opAsync2("op_truncate_async", path, coerceLen(len));
}

function umask(mask) {
Expand All @@ -369,7 +369,7 @@ function linkSync(oldpath, newpath) {
}

async function link(oldpath, newpath) {
await core.opAsync("op_link_async", oldpath, newpath);
await core.opAsync2("op_link_async", oldpath, newpath);
}

function toUnixTimeFromEpoch(value) {
Expand Down Expand Up @@ -499,7 +499,7 @@ function flockSync(rid, exclusive) {
}

async function flock(rid, exclusive) {
await core.opAsync("op_flock_async", rid, exclusive === true);
await core.opAsync2("op_flock_async", rid, exclusive === true);
}

function funlockSync(rid) {
Expand Down
2 changes: 1 addition & 1 deletion ext/http/01_http.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ function createRespondWith(
break;
}
try {
await core.opAsync("op_http_write", streamRid, value);
await core.opAsync2("op_http_write", streamRid, value);
} catch (error) {
const connError = httpConn[connErrorSymbol];
if (
Expand Down
2 changes: 1 addition & 1 deletion ext/node/polyfills/internal/crypto/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function checkPrime(
);
}

core.opAsync(op, candidate, checks).then(
core.opAsync2(op, candidate, checks).then(
(result) => {
callback?.(null, result);
},
Expand Down
2 changes: 1 addition & 1 deletion ext/web/02_timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ const scheduledTimers = { head: null, tail: null };
*/
function runAfterTimeout(cb, millis, timerInfo) {
const cancelRid = timerInfo.cancelRid;
const sleepPromise = core.opAsync("op_sleep", millis, cancelRid);
const sleepPromise = core.opAsync2("op_sleep", millis, cancelRid);
timerInfo.promiseId = sleepPromise[SymbolFor("Deno.core.internalPromiseId")];
if (!timerInfo.isRef) {
core.unrefOp(timerInfo.promiseId);
Expand Down
6 changes: 3 additions & 3 deletions ext/websocket/01_websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ class WebSocket extends EventTarget {
const sendTypedArray = (ta) => {
this[_bufferedAmount] += ta.byteLength;
PromisePrototypeThen(
core.opAsync("op_ws_send_binary", this[_rid], ta),
core.opAsync2("op_ws_send_binary", this[_rid], ta),
() => {
this[_bufferedAmount] -= ta.byteLength;
},
Expand All @@ -322,7 +322,7 @@ class WebSocket extends EventTarget {
const d = core.encode(string);
this[_bufferedAmount] += d.byteLength;
PromisePrototypeThen(
core.opAsync("op_ws_send_text", this[_rid], string),
core.opAsync2("op_ws_send_text", this[_rid], string),
() => {
this[_bufferedAmount] -= d.byteLength;
},
Expand Down Expand Up @@ -394,7 +394,7 @@ class WebSocket extends EventTarget {

async [_eventLoop]() {
while (this[_readyState] !== CLOSED) {
const { 0: kind, 1: value } = await core.opAsync(
const { 0: kind, 1: value } = await core.opAsync2(
"op_ws_next_event",
this[_rid],
);
Expand Down

0 comments on commit aa9b94a

Please sign in to comment.