1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

perf(web): optimize timer resolution (#19493)

Closes https://github.com/denoland/deno/issues/19348

This changes benchmark from the issue from:
```
deno run -A https://raw.githubusercontent.com/nats-io/nats.deno/deno-transport-changes/examples/bench.js --subject a --payload 3500 --pub --count 650000
pub 7,636 msgs/sec - [85.13 secs] ~ 25.49 MB/sec 85127.8765/85127.8765
```
to:
```
> ./target/release/deno run -A https://raw.githubusercontent.com/nats-io/nats.deno/deno-transport-changes/examples/bench.js --subject a --payload 3500 --pub --count 650000
pub 176,840 msgs/sec - [3.68 secs] ~ 590.27 MB/sec 3675.646833/3675.646833

> ./target/release/deno run -A https://raw.githubusercontent.com/nats-io/nats.deno/deno-transport-changes/examples/bench.js --subject a --payload 3500 --pub --count 650000
pub 174,589 msgs/sec - [3.72 secs] ~ 582.76 MB/sec 3723.01925/3723.01925
```
This commit is contained in:
Bartek Iwańczuk 2023-06-14 17:04:49 +02:00 committed by GitHub
parent 5ef225853c
commit 348287825c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -15,7 +15,6 @@ const {
MapPrototypeSet,
Uint8Array,
Uint32Array,
NumberPOSITIVE_INFINITY,
PromisePrototypeThen,
SafeArrayIterator,
SafeMap,
@ -190,7 +189,7 @@ function initializeTimer(
// 13. Run steps after a timeout given global, "setTimeout/setInterval",
// timeout, completionStep, and id.
runAfterTimeout(
() => ArrayPrototypePush(timerTasks, task),
task,
timeout,
timerInfo,
);
@ -203,7 +202,7 @@ function initializeTimer(
/**
* @typedef ScheduledTimer
* @property {number} millis
* @property {() => void} cb
* @property { {action: () => void, nestingLevel: number}[] } task
* @property {boolean} resolved
* @property {ScheduledTimer | null} prev
* @property {ScheduledTimer | null} next
@ -216,12 +215,12 @@ function initializeTimer(
const scheduledTimers = { head: null, tail: null };
/**
* @param {() => void} cb Will be run after the timeout, if it hasn't been
* cancelled.
* @param { {action: () => void, nestingLevel: number}[] } task Will be run
* after the timeout, if it hasn't been cancelled.
* @param {number} millis
* @param {{ cancelRid: number, isRef: boolean, promiseId: number }} timerInfo
*/
function runAfterTimeout(cb, millis, timerInfo) {
function runAfterTimeout(task, millis, timerInfo) {
const cancelRid = timerInfo.cancelRid;
let sleepPromise;
// If this timeout is scheduled for 0ms it means we want it to run at the
@ -241,7 +240,6 @@ function runAfterTimeout(cb, millis, timerInfo) {
/** @type {ScheduledTimer} */
const timerObject = {
millis,
cb,
resolved: false,
prev: scheduledTimers.tail,
next: null,
@ -260,6 +258,10 @@ function runAfterTimeout(cb, millis, timerInfo) {
PromisePrototypeThen(
sleepPromise,
(cancelled) => {
if (timerObject.resolved) {
return;
}
// "op_void_async_deferred" returns null
if (cancelled !== null && !cancelled) {
// The timer was cancelled.
@ -280,18 +282,15 @@ function runAfterTimeout(cb, millis, timerInfo) {
// b) its timeout is lower than the lowest unresolved timeout found so
// far in the list.
timerObject.resolved = true;
let lowestUnresolvedTimeout = NumberPOSITIVE_INFINITY;
let currentEntry = scheduledTimers.head;
while (currentEntry !== null) {
if (currentEntry.millis < lowestUnresolvedTimeout) {
if (currentEntry.resolved) {
currentEntry.cb();
removeFromScheduledTimers(currentEntry);
} else {
lowestUnresolvedTimeout = currentEntry.millis;
if (currentEntry.millis <= timerObject.millis) {
currentEntry.resolved = true;
ArrayPrototypePush(timerTasks, task);
removeFromScheduledTimers(currentEntry);
if (currentEntry === timerObject) {
break;
}
}