mirror of
https://github.com/denoland/deno.git
synced 2025-01-07 06:46:59 -05:00
perf(ext/websocket): use opAsync2 to avoid spread deopt (#18525)
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` | | #18506 | `140079.000000` | | #18506 + #18509 | `150104.250000` | | #18506 + #18509 + this | `157340.000000` |
This commit is contained in:
parent
a23252d975
commit
8088a7b786
8 changed files with 31 additions and 18 deletions
|
@ -191,12 +191,24 @@
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rollPromiseId() {
|
function opAsync2(name, arg0, arg1) {
|
||||||
return nextPromiseId++;
|
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) {
|
function opAsync(name, ...args) {
|
||||||
const id = rollPromiseId();
|
const id = nextPromiseId++;
|
||||||
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
|
let promise = PromisePrototypeThen(setPromise(id), unwrapOpResult);
|
||||||
try {
|
try {
|
||||||
ops[name](id, ...new SafeArrayIterator(args));
|
ops[name](id, ...new SafeArrayIterator(args));
|
||||||
|
@ -376,6 +388,7 @@
|
||||||
// Extra Deno.core.* exports
|
// Extra Deno.core.* exports
|
||||||
const core = ObjectAssign(globalThis.Deno.core, {
|
const core = ObjectAssign(globalThis.Deno.core, {
|
||||||
opAsync,
|
opAsync,
|
||||||
|
opAsync2,
|
||||||
resources,
|
resources,
|
||||||
metrics,
|
metrics,
|
||||||
registerErrorBuilder,
|
registerErrorBuilder,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// then write this fixed 'responseBuf'. The point of this benchmark is to
|
// then write this fixed 'responseBuf'. The point of this benchmark is to
|
||||||
// exercise the event loop in a simple yet semi-realistic way.
|
// 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 requestBuf = new Uint8Array(64 * 1024);
|
||||||
const responseBuf = new Uint8Array(
|
const responseBuf = new Uint8Array(
|
||||||
|
@ -23,7 +23,7 @@ function accept(serverRid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function read(serverRid, buf) {
|
function read(serverRid, buf) {
|
||||||
return opAsync("op_read_socket", serverRid, buf);
|
return opAsync2("op_read_socket", serverRid, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function serve(rid) {
|
async function serve(rid) {
|
||||||
|
|
|
@ -2918,7 +2918,7 @@ pub mod tests {
|
||||||
r#"
|
r#"
|
||||||
|
|
||||||
let zero_copy_a = new Uint8Array([0]);
|
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();
|
.unwrap();
|
||||||
|
|
|
@ -31,7 +31,7 @@ function chmodSync(path, mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chmod(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(
|
function chownSync(
|
||||||
|
@ -121,7 +121,7 @@ async function mkdir(
|
||||||
path,
|
path,
|
||||||
options,
|
options,
|
||||||
) {
|
) {
|
||||||
await core.opAsync("op_mkdir_async", mkdirArgs(path, options));
|
await core.opAsync2("op_mkdir_async", mkdirArgs(path, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
function readDirSync(path) {
|
function readDirSync(path) {
|
||||||
|
@ -349,7 +349,7 @@ function ftruncateSync(rid, len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ftruncate(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) {
|
function truncateSync(path, len) {
|
||||||
|
@ -357,7 +357,7 @@ function truncateSync(path, len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function truncate(path, 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) {
|
function umask(mask) {
|
||||||
|
@ -369,7 +369,7 @@ function linkSync(oldpath, newpath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function link(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) {
|
function toUnixTimeFromEpoch(value) {
|
||||||
|
@ -499,7 +499,7 @@ function flockSync(rid, exclusive) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function flock(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) {
|
function funlockSync(rid) {
|
||||||
|
|
|
@ -316,7 +316,7 @@ function createRespondWith(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await core.opAsync("op_http_write", streamRid, value);
|
await core.opAsync2("op_http_write", streamRid, value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const connError = httpConn[connErrorSymbol];
|
const connError = httpConn[connErrorSymbol];
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -92,7 +92,7 @@ export function checkPrime(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
core.opAsync(op, candidate, checks).then(
|
core.opAsync2(op, candidate, checks).then(
|
||||||
(result) => {
|
(result) => {
|
||||||
callback?.(null, result);
|
callback?.(null, result);
|
||||||
},
|
},
|
||||||
|
|
|
@ -215,7 +215,7 @@ const scheduledTimers = { head: null, tail: null };
|
||||||
*/
|
*/
|
||||||
function runAfterTimeout(cb, millis, timerInfo) {
|
function runAfterTimeout(cb, millis, timerInfo) {
|
||||||
const cancelRid = timerInfo.cancelRid;
|
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")];
|
timerInfo.promiseId = sleepPromise[SymbolFor("Deno.core.internalPromiseId")];
|
||||||
if (!timerInfo.isRef) {
|
if (!timerInfo.isRef) {
|
||||||
core.unrefOp(timerInfo.promiseId);
|
core.unrefOp(timerInfo.promiseId);
|
||||||
|
|
|
@ -301,7 +301,7 @@ class WebSocket extends EventTarget {
|
||||||
const sendTypedArray = (ta) => {
|
const sendTypedArray = (ta) => {
|
||||||
this[_bufferedAmount] += ta.byteLength;
|
this[_bufferedAmount] += ta.byteLength;
|
||||||
PromisePrototypeThen(
|
PromisePrototypeThen(
|
||||||
core.opAsync("op_ws_send_binary", this[_rid], ta),
|
core.opAsync2("op_ws_send_binary", this[_rid], ta),
|
||||||
() => {
|
() => {
|
||||||
this[_bufferedAmount] -= ta.byteLength;
|
this[_bufferedAmount] -= ta.byteLength;
|
||||||
},
|
},
|
||||||
|
@ -322,7 +322,7 @@ class WebSocket extends EventTarget {
|
||||||
const d = core.encode(string);
|
const d = core.encode(string);
|
||||||
this[_bufferedAmount] += d.byteLength;
|
this[_bufferedAmount] += d.byteLength;
|
||||||
PromisePrototypeThen(
|
PromisePrototypeThen(
|
||||||
core.opAsync("op_ws_send_text", this[_rid], string),
|
core.opAsync2("op_ws_send_text", this[_rid], string),
|
||||||
() => {
|
() => {
|
||||||
this[_bufferedAmount] -= d.byteLength;
|
this[_bufferedAmount] -= d.byteLength;
|
||||||
},
|
},
|
||||||
|
@ -394,7 +394,7 @@ class WebSocket extends EventTarget {
|
||||||
|
|
||||||
async [_eventLoop]() {
|
async [_eventLoop]() {
|
||||||
while (this[_readyState] !== CLOSED) {
|
while (this[_readyState] !== CLOSED) {
|
||||||
const { 0: kind, 1: value } = await core.opAsync(
|
const { 0: kind, 1: value } = await core.opAsync2(
|
||||||
"op_ws_next_event",
|
"op_ws_next_event",
|
||||||
this[_rid],
|
this[_rid],
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue