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

[async_wrap] enable/disable PromiseHook depending on kTotals #13509

Closed
wants to merge 3 commits into from

Conversation

trevnorris
Copy link
Contributor

@trevnorris trevnorris commented Jun 6, 2017

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected 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 a CHECK() to Environment::AddPromiseHook() to make sure the same fn + 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/disable AsyncWrap's PromiseHook dynamically.

CI: https://ci.nodejs.org/job/node-test-commit/10405/

@nodejs-github-bot nodejs-github-bot added async_hooks Issues and PRs related to the async hooks subsystem. async_wrap c++ Issues and PRs that require attention from people who are familiar with C++. labels Jun 6, 2017
@trevnorris
Copy link
Contributor Author

@addaleax Thanks much for the code to remove a promise_hook_func from Environment::promise_hooks_. I hadn't thought to compare both the PromiseHookCallback and the arg. Do you think my additional CHECK_EQ() in Environment::AddPromiseHook() is appropriate?

@addaleax
Copy link
Member

addaleax commented Jun 6, 2017

Do you think my additional CHECK_EQ() in Environment::AddPromiseHook() is appropriate?

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.

Copy link
Member

@AndreasMadsen AndreasMadsen left a 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.

// 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]++;
Copy link
Member

@AndreasMadsen AndreasMadsen Jun 6, 2017

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.

Copy link
Contributor Author

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.

Copy link
Member

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?

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@matthewloring

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.

Copy link
Member

@AndreasMadsen AndreasMadsen Jun 8, 2017

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]
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@AndreasMadsen

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?

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.

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,
Copy link
Member

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.

@trevnorris
Copy link
Contributor Author

@AndreasMadsen

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.

Added test. Please double check that it's what you were expecting.

trevnorris and others added 2 commits June 10, 2017 00:14
Allow node::PromiseHook (src/async-wrap.cc) to be enabled/disabled from
the JavaScript API.

PR-URL: nodejs#13509
@trevnorris
Copy link
Contributor Author

@addaleax @AndreasMadsen Needed to include an addon test so I could check the internal field. So running tests one more time

CI: https://ci.nodejs.org/job/node-test-commit/10482/

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
@trevnorris
Copy link
Contributor Author

Test failures are unrelated. I think this is ready to go but would like one more sign-off before landing.

Copy link
Member

@AndreasMadsen AndreasMadsen left a 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.

@addaleax
Copy link
Member

The CI failures are unrelated or infrastructure-related.

Landed in dde4f0f...a2fdb76

@addaleax addaleax closed this Jun 10, 2017
addaleax pushed a commit that referenced this pull request Jun 10, 2017
This reverts commit 410b141.

PR-URL: #13509
Reviewed-By: Andreas Madsen <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
addaleax added a commit that referenced this pull request Jun 10, 2017
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]>
addaleax pushed a commit that referenced this pull request Jun 10, 2017
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]>
@trevnorris trevnorris deleted the async-ktotals branch June 10, 2017 09:52
@trevnorris
Copy link
Contributor Author

@AndreasMadsen @addaleax Thanks much for the reviews and for getting it landed.

@addaleax addaleax mentioned this pull request Jun 10, 2017
addaleax pushed a commit that referenced this pull request Jun 17, 2017
This reverts commit 410b141.

PR-URL: #13509
Reviewed-By: Andreas Madsen <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
addaleax added a commit that referenced this pull request Jun 17, 2017
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]>
addaleax pushed a commit that referenced this pull request Jun 17, 2017
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]>
@addaleax addaleax mentioned this pull request Jun 17, 2017
addaleax pushed a commit that referenced this pull request Jun 21, 2017
This reverts commit 410b141.

PR-URL: #13509
Reviewed-By: Andreas Madsen <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
addaleax added a commit that referenced this pull request Jun 21, 2017
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]>
addaleax pushed a commit that referenced this pull request Jun 21, 2017
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]>
addaleax pushed a commit that referenced this pull request Jun 24, 2017
This reverts commit 410b141.

PR-URL: #13509
Reviewed-By: Andreas Madsen <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
addaleax added a commit that referenced this pull request Jun 24, 2017
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]>
addaleax pushed a commit that referenced this pull request Jun 24, 2017
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]>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
This reverts commit 410b141.

PR-URL: #13509
Reviewed-By: Andreas Madsen <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
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]>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
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]>
addaleax pushed a commit that referenced this pull request Jul 11, 2017
This reverts commit 410b141.

PR-URL: #13509
Reviewed-By: Andreas Madsen <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
addaleax added a commit that referenced this pull request Jul 11, 2017
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]>
addaleax pushed a commit that referenced this pull request Jul 11, 2017
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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
async_hooks Issues and PRs related to the async hooks subsystem. c++ Issues and PRs that require attention from people who are familiar with C++.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants