Closed Bug 1628204 Opened 5 years ago Closed 4 years ago

minor refactoring on dispatching SourceCompressionTask

Categories

(Core :: JavaScript Engine, enhancement, P2)

enhancement

Tracking

()

RESOLVED FIXED
mozilla79
Tracking Status
firefox79 --- fixed

People

(Reporter: allstars.chh, Assigned: allstars.chh)

References

Details

Attachments

(5 files, 6 obsolete files)

47 bytes, text/x-phabricator-request
Details | Review
47 bytes, text/x-phabricator-request
Details | Review
47 bytes, text/x-phabricator-request
Details | Review
47 bytes, text/x-phabricator-request
Details | Review
47 bytes, text/x-phabricator-request
Details | Review

The taskSpecs in HelperThread has a Handler function,
https://searchfox.org/mozilla-central/rev/a707541ff423ade0d81cef6488e6ecfa09273886/js/src/vm/HelperThreads.cpp#2466

And there are many similiar code in each handler, like
Assert(idle());
Assert(CanStart...())

currentTask.emplace(..);

// Handle the task

currentTask.reset();

notify(CONSUMER);

We could move those similar code out of the handlers.
The idea is in the case of Tasks are dispatched to XPCOM thread pool, we could reuse the handler.

Summary: Refactor TaskSpec::Handler in HelperThread for → Refactor TaskSpec::Handler in HelperThread

Hi, Jonco
This is the refactoring for HelperThread as I mentioned last week,
can you give it a look?

Also for the Wasm case, I have a WIP patch in bug 1569819.

Flags: needinfo?(jcoppeard)

(In reply to Yoshi Cheng-Hao Huang [:allstars.chh][:allstarschh] from comment #2)
To be able to use the XPCOM thread pool, we need to split the work that needs to run on the helper thread from the work to select and dispatch tasks. Everything that needs to run on the other thread must be moved into an implementation of RunnableTask::runTask().

This change factors out the work to get the task to run, so this is a good first step. Following on from this, everything in the handleFooTask() methods needs to be either moved into runTask() or into the current thread scheduler. Eventually we should just run the task by calling runTask() in HelperThread::threadLoop.

I'm not sure whether a partial migration to the XPCOM thread pool is going to be possible. There does need to be some kind of scheduling still (as you've seen with the restriction on running as single Wasm job at once) and I don't see how you can have two schedulers at the same time.

Currently scheduling works by picking the next task to run in HelperThread::threadLoop, or waiting for a new task to be queued. That won't work for the XPCOM thread pool because we don't have constantly running threads. Instead we could have a function that checks whether a new task can be scheduled and if so starts it. This would need to be called when every helper thread task is queued and also when every helper thread task finishes. That would let us keep our current scheduling policy.

One direction to approach this from might be to build a simple thread pool for the shell that exposes the same interface as the XPCOM one, and then change the shell to use this first.

Flags: needinfo?(jcoppeard)

Hi Jonco
This is the WIP patch with HelperThreadPool.
This adds a PriorityQueue with js::UniquePtr<RunnableTask>, so when we start an off thread task, like wasm tier2 generator in bug 1569819,
we insert that task into the queue, then the similar threadLoop will fetch the new task from the queue and call runTask() directly.
And PriorityQueue doesn't support move sematics (same for std:priority_queue), so I add a partial specialization for Priorty_Queue with js::UniquePtr.
I haven't run any test yet so it could be very bogus....

could you take a look?
Thanks

Flags: needinfo?(jcoppeard)
Flags: needinfo?(jcoppeard)
Attachment #9141208 - Attachment is obsolete: true
Attachment #9139082 - Attachment is obsolete: true

Hi Jonco
This version I added some check before dispatching the task, please check js::StartOffThreadWasmTier2Generator for detail.
It will check if we have avaialble thread and this task could be dispatched, and if so, we call HelperThreadTaskCallback to dispatch it.

Meanwhile there's a threadLoopNew() and canDispatch.*Task() functions, which are similar to original threadLoop() and canStart.*Task()
I'll try to merge them later.

So far the task dispatched to SM HelperThreads still uses the same way, we push to the corresponding task queue, and HelperThread checks getHighestPriorityTask() and run it. (see threadLoopNew())

For XPCOM thread we make sure there are still available threads and the task doesn't exceed its limit, then we dispatch the getHighestPriorityTask() to XPCOM thread pool, and when the RunnableTask is about to finished, we call a callback in GlobalHelperThreadState to see if there's another high priority task, and if there is, we dispatch the next high priority task again.

Could you check this?

Thanks

Flags: needinfo?(jcoppeard)
Flags: needinfo?(jcoppeard)
Attachment #9142314 - Attachment is obsolete: true

After fixed bug 1634720 I went back to review my patches, and found one simpler way to implement this. So far this is still WIP, but at least the try on linux64(debug + opt) are all green. There're still some ongoing patches will be added.

(In reply to Yoshi Cheng-Hao Huang [:allstars.chh][:allstarschh] from comment #10)
I'm not sure about this approach. If I understand correctly, this runs our current helper thread loop in an XPCOM runnable task. This won't play fair with other users of the thread pool that may be starved if we continually run tasks.

(In reply to Jon Coppeard (:jonco) from comment #11)

I'm not sure about this approach. If I understand correctly, this runs our current helper thread loop in an XPCOM runnable task. This won't play fair with other users of the thread pool that may be starved if we continually run tasks.
Yes, the HelperThread running on XPCOM thread will keep running the tasks until all the tasks are executed. Then the thread will return to HelperThreadPool.
I thought this was okay because normally SM dispatches more than 1 SourceComressionTasks to HelperThreads.

I'll update the patch to let it run only 1 task from queue, once the task is finished it will check if the queue is empty, if not empty it will schedule another RunnableTask to XPCOM thread pool.

That would be better but I'm still not sure this is the right approach. Really we need to have a separate abstraction for a task than a thread.

Added a mShutdown to prevent thread race and leak when nsThreadPool is shutdown.
This is needed because the dispatch() will be called on a non-main
thread.

Attachment #9149357 - Attachment is obsolete: true
Attachment #9149823 - Attachment description: Bug 1628204 - Add a dispatch function for dispatching tasks to XPCOM thread pool → Bug 1628204 - Add a dispatch function for dispatching tasks.

Jonco, can you check the patch and give me some comments?

Thanks

Flags: needinfo?(jcoppeard)

(In reply to Yoshi Cheng-Hao Huang [:allstars.chh][:allstarschh] from comment #16)
Comments in phabricator.

Flags: needinfo?(jcoppeard)

Jonco, I just update the code with your comments addressed, could you check it?
Thanks

Flags: needinfo?(jcoppeard)
Flags: needinfo?(jcoppeard)

ni? jonco again for the updated patches, thanks

Flags: needinfo?(jcoppeard)

https://phabricator.services.mozilla.com/D78461 moves the code inside runTask,
however it still has some asan failures
https://treeherder.mozilla.org/#/jobs?repo=try&revision=2a4e213567f7c6a30e1efd16977d80e10d535052&selectedTaskRun=e1q_9sOOSxmLVLOnhbaIPQ-0

The reason is originally "append to compressionFinishList" and currentTask.reset() will be executed atomically, but now there's an extra unlock before currentTask.reset(), and other thread executes AttachToFinishList and deletes the pointer, and now 3rd thread calls CancelOffThreadCompressionTask and try to get helper.compressionTask(), but the pointer has been deleted.

Hi Jonco
Or does it make sense to call SourceCompressionTask->complete() after runTask on a helper thread?
Now I got a TSAN failure, one is a helper thread calling complete(), and the main thread is calling trace().

fixed to heap-use-after-free problem by delaying the timing when the SourceCompresionsTask is release from compressionFinishedList.

Flags: needinfo?(jcoppeard)
Attachment #9154479 - Attachment description: Bug 1628204 - Move to compressionFinishedList inside runTask. → Bug 1628204 - Move append to compressionFinishedList inside runTask.
Attachment #9149356 - Attachment description: Bug 1628204 - Check if gHelperThread still exists. → Bug 1628204 - Part 1: Check if gHelperThread still exists.
Attachment #9154479 - Attachment description: Bug 1628204 - Move append to compressionFinishedList inside runTask. → Bug 1628204 - Part 2: Move append to compressionFinishedList inside runTask.
Attachment #9149823 - Attachment description: Bug 1628204 - Add a dispatch function for dispatching tasks. → Bug 1628204 - Part 3: Add a dispatch function for dispatching tasks.
Attachment #9149824 - Attachment description: Bug 1628204 - Add mShutdown for HelperThreadPool → Bug 1628204 - Part 4: Add mShutdown for HelperThreadPool

So far I found there are some tests on try will have leak, still figuring out where the leak is from.
I've tried to make all subclasses of RunnableTasks like SourceCompressionTask, ParseTask, wasm::Tier2Generator, IonCompileTask .... to inherit HelperTask, but IonCompileTasks seems to have more problems (I found many assertions related to IonScript, IonCompileTask in my try push), so in the end I've only made SourceComressionTask inherit HelperTask, other tasks remain the same (inherit RunnableTask).

(In reply to Yoshi Cheng-Hao Huang [:allstars.chh][:allstarschh] from comment #21)

https://phabricator.services.mozilla.com/D78461 moves the code inside runTask,
however it still has some asan failures
https://treeherder.mozilla.org/#/jobs?repo=try&revision=2a4e213567f7c6a30e1efd16977d80e10d535052&selectedTaskRun=e1q_9sOOSxmLVLOnhbaIPQ-0

The reason is originally "append to compressionFinishList" and currentTask.reset() will be executed atomically, but now there's an extra unlock before currentTask.reset(), and other thread executes AttachToFinishList and deletes the pointer, and now 3rd thread calls CancelOffThreadCompressionTask and try to get helper.compressionTask(), but the pointer has been deleted.

Updated the patch with jonco's comment https://phabricator.services.mozilla.com/D78461#inline-456075
now runTaskImpl takes a lock can fix this.

(In reply to Yoshi Cheng-Hao Huang [:allstars.chh][:allstarschh] from comment #24)

So far I found there are some tests on try will have leak, still figuring out where the leak is from.
The leak is calling nsThreadPool::Dispatch while it's shutdown, filed the bug 1645153

Jonco, can you look the latest patch again? Thanks

Flags: needinfo?(jcoppeard)
Attachment #9154479 - Attachment description: Bug 1628204 - Part 2: Move append to compressionFinishedList inside runTask. → Bug 1628204 - Part 1: Move append to compressionFinishedList inside runTask.
Attachment #9149356 - Attachment description: Bug 1628204 - Part 1: Check if gHelperThread still exists. → Bug 1628204 - Part 4: Check if gHelperThread still exists.
Attachment #9149824 - Attachment description: Bug 1628204 - Part 4: Add mShutdown for HelperThreadPool → Bug 1628204 - Part 5: Add mShutdown for HelperThreadPool.

revert https://phabricator.services.mozilla.com/D74736

In handleCompression the task will be moved to compressionFinishedList
and later main thread will use compressionFinishedList to do the
finishing.

So we need to release the ownership otherwise the task will be
released by HelperThreadTaskHandler.

Attachment #9156183 - Attachment description: Bug 1628204 - Part 5: Don't submit compression tasks after shutdown. → Bug 1628204 - Part 7: Don't submit compression tasks after shutdown.

Updated the part 3 patch, so we don't dispatch to XPCOM at the moment.

Attachment #9156183 - Attachment description: Bug 1628204 - Part 7: Don't submit compression tasks after shutdown. → Bug 1628204 - Part 2: Don't submit compression tasks after shutdown.
Flags: needinfo?(jcoppeard)
Pushed by allstars.chh@gmail.com: https://hg.mozilla.org/integration/autoland/rev/7a81a85d9881 Part 1: Move append to compressionFinishedList inside runTask. r=jonco https://hg.mozilla.org/integration/autoland/rev/8050fb033d92 Part 2: Don't submit compression tasks after shutdown. r=jonco
Status: ASSIGNED → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla79
Summary: Refactor TaskSpec::Handler in HelperThread → minor refactoring on dispatching SourceCompressionTask
Regressions: 1647115
Attachment #9149824 - Attachment is obsolete: true
Attachment #9149356 - Attachment is obsolete: true
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: