-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
async_hooks: execute destroy hooks earlier #34342
Conversation
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? |
Can you add a test that verifies that this also works when (That complexity is why I haven’t opened a PR myself yet) |
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)
How can I enforce this? I guess calling |
@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.) |
cc9aa0d
to
3b62014
Compare
@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? |
@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 :) |
No need to hurry. I'm on vacation next week and will not find any time this week. |
Local run benchmarks show some degrades (CI still hangs).
Full result
|
@Flarna Okay, I’ll just try to push something here then (and maybe also take care of the perf regression :)) |
@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? |
Looks fine. it should be also quite easy to craft a test for this. |
Yes :) I think that way we get a best-of-both-worlds result. |
3b62014
to
c10f59f
Compare
This comment has been minimized.
This comment has been minimized.
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
|
Yes, checking |
c10f59f
to
9c7b852
Compare
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.
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: #34342 Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
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: #34342 Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
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: #34342 Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
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: #34342 Fixes: #34328 Refs: #33896 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
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