-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
[async_wrap] enable/disable PromiseHook
depending on kTotals
#13509
Conversation
@addaleax Thanks much for the code to remove a |
Yeah, I think it’s a good idea until we know it’s not – if somebody actually has a use case for attaching identical handlers, we can always drop the check again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I just have a few comments.
edit: Maybe add a test where a promise is created and resolved after the promise hooks are disabled. Just to check that disablePromiseHook
works as expected.
lib/async_hooks.js
Outdated
// createHook() has already enforced that the callbacks are all functions, | ||
// so here simply increment the count of whether each callbacks exists or | ||
// not. | ||
hook_fields[kInit] += +!!this[init_symbol]; | ||
hook_fields[kBefore] += +!!this[before_symbol]; | ||
hook_fields[kAfter] += +!!this[after_symbol]; | ||
hook_fields[kDestroy] += +!!this[destroy_symbol]; | ||
hook_fields[kTotals]++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a silly edge case, but what if there aren't provided any hooks then we don't need to enable promises.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked @matthewloring about this on IRC:
<trevnorris> if an async hook is enabled that has no callbacks should we go through
the trouble of setting up the PromiseWrap in async_wrap.cc PromiseHook?
<mattloring> Is it expected to be a common case to have async hooks enabled with no
listeners? If listeners are added later then it might be good to have
PromiseWraps available to resolve parent promise ids
<trevnorris> it isn't a common case, but i can see your point. so continue to add
PromiseWraps to Promises even if there are no callbacks to be called.
@AndreasMadsen My original PR tracked the number of callbacks to be called, and only called enablePromiseHook()
if the number of callbacks was > 0
. If you think it should be difference feel free to chime in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what @matthewloring mean with:
If listeners are added later then it might be good to have PromiseWraps available to resolve parent promise ids.
Is this related to #13427?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, reading back over it the comment wasn't correct. I was thinking about the case where async hooks are enabled in the middle of executing a promise chain and the parent promise is not wrapped but I forgot this was handled by adding a silent mode wrap when the child promise is created (https://github.com/trevnorris/node/blob/5a61e784c9b4f03a1341970a0b81819a52a60dde/src/async-wrap.cc#L309). However, the first part of the comment still holds. I was curious whether having async hooks enabled with no callbacks registered was expected to occur frequently enough to make it worth optimizing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was curious whether having async hooks enabled with no callbacks registered was expected to occur frequently enough to make it worth optimizing?
I doubt it's a common case. Honestly I'm looking for what is the most expected behavior, but since creating a new hook w/o any callbacks isn't an expected behavior not sure what to say. Which behavior would you expect?
@AndreasMadsen Personally I like this solution more because the logic is much simpler. Though I can also keep track of number of callbacks as well. I'll leave the call as to what should be done up to others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt it's a common case. Honestly I'm looking for what is the most expected behavior, but since creating a new hook w/o any callbacks isn't an expected behavior not sure what to say. Which behavior would you expect?
I will expect async_hooks
to have the smallest performance impact possible. This includes not enabling promise hooks when there are no hooks.
Personally I like this solution more because the logic is much simpler.
Yeah, that is the one reason why I don't like the additional checks. But I think especially in async_hooks
performance is preferred over simplicity. It is also not that difficult/complex to check:
hook_fields[kTotal] += +(
!!this[init_symbol] || !!this[before_symbol] ||
!!this[after_symbol] || !!this[destroy_symbol]
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is also not that difficult/complex to check:
You're correct, and that's similar to the check I had before changing it to what's here now.
@matthewloring You agree that Promise hooks should only be enabled if there's actually a callback to call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, I don't see any other reason they need to be active.
lib/async_hooks.js
Outdated
let setupHooksCalled = false; | ||
// Setup the callbacks that node::AsyncWrap will call when there are hooks to | ||
// process. They use the same functions as the JS embedder API. | ||
async_wrap.setupHooks({ init, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment explaining why we do this immediately instead of waiting for the AsyncHook.enable()
call.
Added test. Please double check that it's what you were expecting. |
This reverts commit 410b141. PR-URL: nodejs#13509
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: nodejs#13509
5a61e78
to
8e95f26
Compare
@addaleax @AndreasMadsen Needed to include an addon test so I could check the internal field. So running tests one more time |
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: nodejs#13509
8e95f26
to
5fa59cc
Compare
Test failures are unrelated. I think this is ready to go but would like one more sign-off before landing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
The kTotals
setup is a little hard to read. You could just do:
hook_fields[kTotals] = hook_fields[kInit] + hook_fields[kBefore] + hook_fields[kAfter] + hook_fields[kDestroy]
but it is not important to me.
The CI failures are unrelated or infrastructure-related. Landed in dde4f0f...a2fdb76 |
This reverts commit 410b141. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
@AndreasMadsen @addaleax Thanks much for the reviews and for getting it landed. |
This reverts commit 410b141. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
This reverts commit 410b141. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
This reverts commit 410b141. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
This reverts commit 410b141. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
This reverts commit 410b141. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from the JavaScript API. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Keep a total of enabled hook callbacks in kTotals. This value is used to track whether node::PromiseHook (src/async-wrap.cc) should be enabled or disabled. Don't enable node::PromiseHook, using enablePromiseHook(), until a hook has been added. Then, using disablePromiseHook(), disable node::PromiseHook when all hooks have been disabled. Need to use a native test in order to check the internal field of the Promise and check for a PromiseWrap. PR-URL: #13509 Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
async_wrap, async_hooks
Description
First revert 410b141. There's no need to delay setting the callbacks. No native logic exists that checks if these are empty or not. Except the check that occurs just before setting them.
Then use a portion of #13416 to allow removing a PromiseHook from
Environment::promise_hooks_
, and add aCHECK()
toEnvironment::AddPromiseHook()
to make sure the samefn
+arg
isn't added twice. (@addaleax I kept you as the author)Finally track the number of enabled hooks via
kTotals
and use that to enable/disableAsyncWrap
'sPromiseHook
dynamically.CI: https://ci.nodejs.org/job/node-test-commit/10405/