Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.3k
async_hooks: execute destroy hooks earlier#34342
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_hooks: execute destroy hooks earlier #34342
Uh oh!
There was an error while loading. Please reload this page.
Conversation
Flarna commented Jul 13, 2020 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Flarna commented Jul 13, 2020
Not sure at all if this change should be done/is really helpful as such long running promise chains as in #34328 block IO so most likely not a typical usecase - except maybe in workers? |
addaleax commented Jul 13, 2020 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Can you add a test that verifies that this also works when (That complexity is why I haven’t opened a PR myself yet) |
addaleax left a comment
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.
(Marking requested changes since having an explicit test verifying that the typical use case isn’t broken is a blocker for me, and ideally this should also come with a regression test of its own)
Flarna commented Jul 13, 2020
How can I enforce this? I guess calling |
addaleax commented Jul 13, 2020
@Flarna Yeah, it’s tricky – V8 doesn’t provide any way to do this, afaik, so what I think we’ve done in the past is to allocate a lot of objects, but not too many, so that GC is triggered, but as a background task instead of as an interrupt. (Alternatively, I think you could just queue an immediate + a microtask, separately.) |
Uh oh!
There was an error while loading. Please reload this page.
cc9aa0d to 3b62014CompareFlarna commented Jul 16, 2020
@addaleax Is the test I added what you expected or should I play around a little bit more? I tried also to run benchmarks for async_hooks but they hang after a while. Is this a known issue or does this indicated that this change causes problems? |
addaleax commented Jul 16, 2020
@Flarna What I had in mind for testing is something that verifies that this works even when a native weak AsyncWrap object (e.g. My understanding is that this does work, but it’s tricky to test because intentionally causing a background GC to run is not trivial. But I also realize that it might be annoying that my review is currently blocking this, so I can put in some time tomorrow to write a test myself and push that to this PR so that you don’t need to write a test like that yourself :) |
Flarna commented Jul 16, 2020
No need to hurry. I'm on vacation next week and will not find any time this week. |
Flarna commented Jul 17, 2020
Local run benchmarks show some degrades (CI still hangs). Full result |
addaleax commented Jul 17, 2020
@Flarna Okay, I’ll just try to push something here then (and maybe also take care of the perf regression :)) |
addaleax commented Jul 17, 2020
@Flarna How about this? diff --git a/src/async_wrap.cc b/src/async_wrap.cc index f53c53999471..add88aaac536 100644 --- a/src/async_wrap.cc+++ b/src/async_wrap.cc@@ -782,6 +782,11 @@ void AsyncWrap::EmitDestroy(Environment* env, double async_id){} if (env->destroy_async_id_list()->empty()){+ env->SetImmediate(DestroyAsyncIdsCallback, CallbackFlags::kUnrefed);+ }+ // If the list gets very large, try scheduling a microtask to empty it+ // at an earlier point in time.+ if (env->destroy_async_id_list()->size() == 16384){ env->isolate()->EnqueueMicrotask(DestroyAsyncIdsCallback, env)} it keeps performance where it is right but, but still keeps the id list from filling up without limit in the cases in which we can empty it through a microtask? |
Flarna commented Jul 17, 2020
Looks fine. it should be also quite easy to craft a test for this. |
addaleax commented Jul 17, 2020
Yes :) I think that way we get a best-of-both-worlds result. |
3b62014 to c10f59fCompare This comment has been minimized.
This comment has been minimized.
nodejs-github-bot commented Jul 28, 2020
Flarna commented Jul 28, 2020
Seems that this doesn't work in some cases as CI shows a crash in node-test-commit-linux-containered for ubuntu1804_sharedlibs_debug_x64 (see https://ci.nodejs.org/job/node-test-commit-linux-containered/21528/). I think the crash could be avoided by checking |
Flarna commented Jul 28, 2020
Yes, checking |
c10f59f to 9c7b852Compare This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
nodejs-github-bot commented Jul 30, 2020
nodejs-github-bot commented Jul 31, 2020
Use a microtask to call destroy hooks in case there are a lot queued as immediate may be scheduled late in case of long running promise chains. Queuing a mircrotasks in GC context is not allowed therefore an interrupt is triggered to do this in JS context as fast as possible. fixes: #34328 refs: #33896 PR-URL: #34342Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
Flarna commented Aug 2, 2020
Landed in cb142d1 |
Use a microtask to call destroy hooks in case there are a lot queued as immediate may be scheduled late in case of long running promise chains. Queuing a mircrotasks in GC context is not allowed therefore an interrupt is triggered to do this in JS context as fast as possible. fixes: #34328 refs: #33896 PR-URL: #34342Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
Use a microtask to call destroy hooks in case there are a lot queued as immediate may be scheduled late in case of long running promise chains. Queuing a mircrotasks in GC context is not allowed therefore an interrupt is triggered to do this in JS context as fast as possible. fixes: #34328 refs: #33896 PR-URL: #34342Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
Use a microtask to call destroy hooks in case there are a lot queued as immediate may be scheduled late in case of long running promise chains. Queuing a mircrotasks in GC context is not allowed therefore an interrupt is triggered to do this in JS context as fast as possible. fixes: #34328 refs: #33896 PR-URL: #34342Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]>
Use a microtask to call destroy hooks in case there are a lot queued as immediate may be scheduled late in case of long running
promise chains.
Queuing a mircrotasks in GC context is not allowed therefore an interrupt is triggered to do this in JS context as fast as possible.
fixes: #34328
refs: #33896