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