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

Limit foreground task draining loop in NodePlatform #19937

Closed
ulan opened this issue Apr 11, 2018 · 9 comments
Closed

Limit foreground task draining loop in NodePlatform #19937

ulan opened this issue Apr 11, 2018 · 9 comments
Labels
v8 engine Issues and PRs related to the V8 dependency. v8 platform Issues and PRs related to Node's v8::Platform implementation.

Comments

@ulan
Copy link
Contributor

ulan commented Apr 11, 2018

See https://groups.google.com/forum/#!topic/v8-users/tunDe2yVUoQ for the context.

Currently the NodePlatform drains the foreground_tasks_ queue until the queue becomes empty:
while (std::unique_ptr task = foreground_tasks_.Pop()) {
did_work = true;
RunForegroundTask(std::move(task));
}

This does not work well for tasks that re-post themselves. An example of such tasks is incremental marking task that does 1ms marking work and re-posts itself.

With the current loop draining implementation, incremental marking effectively becomes non-incremental because the loop stops only when incremental marking finishes.

I would like to propose to limit the draining loop to the number of tasks that were in the queue at the start of the loop. The re-posted tasks would be processed via libuv, which would give other tasks (like JS code) chance to run.

@bnoordhuis
Copy link
Member

Sounds reasonable to me. Pop() should probably be replaced with a method that does task_queue_.swap(...).

@addaleax Good idea / bad idea?

@ulan
Copy link
Contributor Author

ulan commented Apr 11, 2018

@bnoordhuis, @addaleax, another possible fix assuming that the queue is FIFO:

size_t limit = foreground_tasks.Size();
for (size_t i = 0; i < limit && (task = foreground_tasks_.Pop()); ++i) {
    did_work = true;
    RunForegroundTask(std::move(task));  
}

The same for the delayed tasks.

We probably need an option for FlushForegroundTasksInternal to drain all the tasks, because it is also used the destructor of PerIsolatePlatformData.

@ryzokuken
Copy link
Contributor

@bnoordhuis @addaleax I'm terrible at C++ work, and haven't submitted a single C++ PR yet, but I'd love to get more into that side of things in the codebase.

If any of you would be willing to provide a little guidance regarding this one, I think I could take it up.

@bnoordhuis
Copy link
Member

@ryzokuken Sure thing. If you have specific questions, I'll try to answer them.

@ryzokuken
Copy link
Contributor

@bnoordhuis Great, thanks. I'll be posting things in here as they come up, then.

@ulan
Copy link
Contributor Author

ulan commented Apr 12, 2018

@ryzokuken @bnoordhuis, oh, I was planning to work on this since I already did debugging. I should have mentioned that before, sorry. I was waiting for @addaleax's reply and the decision on whether to go with swap or limit approach before uploading PR.

@ryzokuken, did you already start working on this?

@ryzokuken
Copy link
Contributor

@ulan I haven't done much, if you've started working on this, please go ahead.

@addaleax addaleax added the v8 engine Issues and PRs related to the V8 dependency. label Apr 12, 2018
@addaleax
Copy link
Member

@ulan I would go with the swapping solution like Ben suggested, but mostly because that seems simpler and doesn’t require setting some slightly arbitrary value as a limit. If you think that V8 has different requirements, feel free to ignore me. :)

@ulan
Copy link
Contributor Author

ulan commented Apr 12, 2018

@addaleax, thanks! I implemented the swap approach.

MylesBorins pushed a commit that referenced this issue May 4, 2018
Foreground tasks that repost themselves can force the draining loop
to run indefinitely long without giving other tasks chance to run.

This limits the foreground task draining loop to run only the tasks
that were in the tasks queue at the beginning of the loop.

PR-URL: #19987
Fixes: #19937
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yang Guo <yangguo@chromium.org>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Khaidi Chu <i@2333.moe>
blattersturm pushed a commit to citizenfx/node that referenced this issue Nov 3, 2018
Foreground tasks that repost themselves can force the draining loop
to run indefinitely long without giving other tasks chance to run.

This limits the foreground task draining loop to run only the tasks
that were in the tasks queue at the beginning of the loop.

PR-URL: nodejs#19987
Fixes: nodejs#19937
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yang Guo <yangguo@chromium.org>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Khaidi Chu <i@2333.moe>
@addaleax addaleax added the v8 platform Issues and PRs related to Node's v8::Platform implementation. label Feb 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v8 engine Issues and PRs related to the V8 dependency. v8 platform Issues and PRs related to Node's v8::Platform implementation.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants