Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timers: allow timers to be used as primitives #21152

Closed

Conversation

apapirovski
Copy link
Member

This continues on @bmeck's excellent idea and work in #19683. With their permission, I made some additional changes to improve the performance and fix a memory leak. This way we shouldn't see any (or certainly very minimal) regression in our benchmarks, at least judging by running them locally.

For web compatibility this allows timers to be stored as the key of an Object property and be passed back to corresponding method to clear the timer.

Refs: #19683
Co-authored-by: Bradley Farias [email protected]

@bmeck I had to give you credit as co-author using github's metadata as it was too much work to rebase the original. Hopefully not a huge deal (but definitely let me know)?

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

For web compatibility this allows timers to be stored as the key
of an Object property and be passed back to corresponding method to
clear the timer.

Co-authored-by: Bradley Farias <[email protected]>
@apapirovski apapirovski added the timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. label Jun 5, 2018
@bmeck
Copy link
Member

bmeck commented Jun 5, 2018

+1, don't worry about attribution here.

@apapirovski apapirovski added the semver-minor PRs that contain new features and should be released in the next minor version. label Jun 5, 2018
@mscdex
Copy link
Contributor

mscdex commented Jun 5, 2018

The double digit performance regressions still worry me.

@apapirovski
Copy link
Member Author

@mscdex Let me see what's going on. This doesn't match what I'm seeing locally... I'm also noticing a wide spread in the results. Let's run it again, not convinced the timers benchmarks are precise enough on the linux machine for some reason.

Benchmark CI: https://ci.nodejs.org/view/Node.js%20benchmark/job/benchmark-node-micro-benchmarks/206/

if (timerInstance !== undefined) {
timerInstance._onTimeout = null;
unenroll(timerInstance);
}
Copy link
Member

@jdalton jdalton Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👆 In the browser implementations I think there is some coercion going on as:

var i = setTimeout(()=>console.log("hi"), 1000);
clearTimeout({ [Symbol.toPrimitive]() { return i } })
// will clear the time

Would it make sense to instead of type checking just coerce the value to a number
(or whatever the correct steps may be).

@@ -123,6 +123,14 @@ Calling `timeout.unref()` creates an internal timer that will wake the Node.js
event loop. Creating too many of these can adversely impact performance
of the Node.js application.

### timeout[Symbol.toPrimitive]()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is rendered as an empty link in the GitHub and in HTML:

l

Copy link
Contributor

@vsemozhetbyt vsemozhetbyt Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ Should this section be placed before the timeout.unref() heading ABC-wise?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it depends on what convention we follow for symbols. I prefer it after but it could also be the first thing in the list. I wouldn't put it between ref & unref.

Will fix the link issue 👍


When coercing a `Timeout` to a primitive, a primitive will be generated that
can be used to clear the `Timeout`. This allows enhanced compatibility with
browser `setTimeout`, and `setInterval` implementations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`setTimeout` -> `setTimeout()`?
`setInterval` -> `setInterval()`?

@mscdex
Copy link
Contributor

mscdex commented Jun 6, 2018

Benchmark results still seem to be about the same (double digit regressions), despite the increased number of runs.

@apapirovski
Copy link
Member Author

Yeah, I'm going to investigate at some point this week and see if it can be fixed. It's frustrating that this doesn't match what I'm seeing locally.

@@ -347,6 +353,9 @@ function tryOnTimeout(timer, start) {
refCount--;
timer[kRefed] = null;

if (timer[kHasPrimitive])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might === true be faster?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't, hopefully? I think the problem is with symbols but I don't want to do this with a public prop. Maybe @nodejs/v8 can provide some input? Any chance of symbol access getting faster in the future? From what I've seen it's currently quite a bit slower than string props.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @bnoordhuis mentioned at some point that it was a bit faster.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what output turbolizer would give for this, this still doesn't seem right so I can only imagine it would be a polymorphism problem

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's polymorphism. In the benchmark we don't call this with any values but timer objects. I'm reasonably certain it's the symbol because I've run into this a bunch while working on timers & http2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh whoops, I was thinking of the wrong function

return;
}

const timerType = typeof timer;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typeof checks are fast IIRC

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and I think they are even faster that caching the value like this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if doing the checks and then turning this into an else if would reduce speculative branching and help?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caching typeof used to be a lot slower than using it inline, at least with Crankshaft, not sure about TurboFan.

// This stores all the known timer async ids to allow users to clearTimeout and
// clearInterval using those ids, to match the spec and the rest of the web
// platform.
const knownTimersById = Object.create(null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the keys are going to be numbers, could a holey array be faster?

@jasnell
Copy link
Member

jasnell commented Sep 10, 2018

What's the status on this one?

@jasnell jasnell added the stalled Issues and PRs that are stalled. label Sep 10, 2018
@BridgeAR
Copy link
Member

Ping @apapirovski it would be great to move this forward.

@apapirovski
Copy link
Member Author

@BridgeAR ya, it got held up on performance concerns. Will revisit again.

@apapirovski
Copy link
Member Author

This will PR will land one day... maybe... I hope 😞

@BridgeAR
Copy link
Member

@apapirovski do you think you might find some time to have a look at this some time soon again?

@BridgeAR BridgeAR force-pushed the master branch 2 times, most recently from 8ae28ff to 2935f72 Compare May 31, 2020 12:20
@jasnell
Copy link
Member

jasnell commented Jun 19, 2020

There's been no further activity, unfortunately. Closing. Can reopen if someone wants to pick it back up

@jasnell jasnell closed this Jun 19, 2020
lundibundi added a commit to lundibundi/node that referenced this pull request Jun 23, 2020
This allows timers to be matched to numeric Ids and therefore used
as keys of an Object, passed and stored without storing the Timer instance.

clearTimeout/clearInterval is modified to support numeric/string Ids.

Co-authored-by: Bradley Farias <[email protected]>
Co-authored-by: Anatoli Papirovski <[email protected]>

Refs: nodejs#21152
jasnell pushed a commit that referenced this pull request Jun 24, 2020
This allows timers to be matched to numeric Ids and therefore used
as keys of an Object, passed and stored without storing the Timer instance.

clearTimeout/clearInterval is modified to support numeric/string Ids.

Co-authored-by: Bradley Farias <[email protected]>
Co-authored-by: Anatoli Papirovski <[email protected]>

Refs: #21152

PR-URL: #34017
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Bradley Farias <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
lundibundi added a commit to lundibundi/node that referenced this pull request Jul 22, 2020
This allows timers to be matched to numeric Ids and therefore used
as keys of an Object, passed and stored without storing the Timer instance.

clearTimeout/clearInterval is modified to support numeric/string Ids.

Co-authored-by: Bradley Farias <[email protected]>
Co-authored-by: Anatoli Papirovski <[email protected]>

Refs: nodejs#21152

PR-URL: nodejs#34017
Backport-PR-URL: nodejs#34482
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Bradley Farias <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Signed-off-by: Denys Otrishko <[email protected]>
MylesBorins pushed a commit that referenced this pull request Aug 17, 2020
This allows timers to be matched to numeric Ids and therefore used
as keys of an Object, passed and stored without storing the Timer instance.

clearTimeout/clearInterval is modified to support numeric/string Ids.

Co-authored-by: Bradley Farias <[email protected]>
Co-authored-by: Anatoli Papirovski <[email protected]>

Refs: #21152

Backport-PR-URL: #34482
PR-URL: #34017
Backport-PR-URL: #34482
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Bradley Farias <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Signed-off-by: Denys Otrishko <[email protected]>
addaleax pushed a commit that referenced this pull request Sep 22, 2020
This allows timers to be matched to numeric Ids and therefore used
as keys of an Object, passed and stored without storing the Timer instance.

clearTimeout/clearInterval is modified to support numeric/string Ids.

Co-authored-by: Bradley Farias <[email protected]>
Co-authored-by: Anatoli Papirovski <[email protected]>

Refs: #21152

Backport-PR-URL: #34482
PR-URL: #34017
Backport-PR-URL: #34482
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Bradley Farias <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Signed-off-by: Denys Otrishko <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-minor PRs that contain new features and should be released in the next minor version. stalled Issues and PRs that are stalled. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants