1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef gc_ParallelWork_h
8 #define gc_ParallelWork_h
10 #include "mozilla/Maybe.h"
14 #include "gc/GCParallelTask.h"
15 #include "gc/GCRuntime.h"
16 #include "js/SliceBudget.h"
17 #include "vm/HelperThreads.h"
22 enum class PhaseKind
: uint8_t;
27 template <typename WorkItem
>
28 using ParallelWorkFunc
= size_t (*)(GCRuntime
*, const WorkItem
&);
30 // A GCParallelTask task that executes WorkItems from a WorkItemIterator.
32 // The WorkItemIterator class must supply done(), next() and get() methods. The
33 // get() method must return WorkItems objects.
34 template <typename WorkItem
, typename WorkItemIterator
>
35 class ParallelWorker
: public GCParallelTask
{
37 using WorkFunc
= ParallelWorkFunc
<WorkItem
>;
39 ParallelWorker(GCRuntime
* gc
, gcstats::PhaseKind phaseKind
, GCUse use
,
40 WorkFunc func
, WorkItemIterator
& work
,
41 const SliceBudget
& budget
, AutoLockHelperThreadState
& lock
)
42 : GCParallelTask(gc
, phaseKind
, use
),
47 // Consume a work item on creation so that we can stop creating workers if
48 // the number of workers exceeds the number of work items.
52 void run(AutoLockHelperThreadState
& lock
) {
53 AutoUnlockHelperThreadState
unlock(lock
);
56 size_t steps
= func_(gc
, item_
);
57 budget_
.step(std::max(steps
, size_t(1)));
58 if (budget_
.isOverBudget()) {
62 AutoLockHelperThreadState lock
;
73 WorkItemIterator
& work() { return work_
.ref(); }
75 // A function to execute work items on the helper thread.
78 // An iterator which produces work items to execute.
79 HelperThreadLockData
<WorkItemIterator
&> work_
;
81 // The budget that determines how long to run for.
84 // The next work item to process.
88 static constexpr size_t MaxParallelWorkers
= 8;
90 // An RAII class that starts a number of ParallelWorkers and waits for them to
92 template <typename WorkItem
, typename WorkItemIterator
>
93 class MOZ_RAII AutoRunParallelWork
{
95 using Worker
= ParallelWorker
<WorkItem
, WorkItemIterator
>;
96 using WorkFunc
= ParallelWorkFunc
<WorkItem
>;
98 AutoRunParallelWork(GCRuntime
* gc
, WorkFunc func
,
99 gcstats::PhaseKind phaseKind
, GCUse use
,
100 WorkItemIterator
& work
, const SliceBudget
& budget
,
101 AutoLockHelperThreadState
& lock
)
102 : gc(gc
), phaseKind(phaseKind
), lock(lock
), tasksStarted(0) {
103 size_t workerCount
= gc
->parallelWorkerCount();
104 MOZ_ASSERT(workerCount
<= MaxParallelWorkers
);
105 MOZ_ASSERT_IF(workerCount
== 0, work
.done());
107 for (size_t i
= 0; i
< workerCount
&& !work
.done(); i
++) {
108 tasks
[i
].emplace(gc
, phaseKind
, use
, func
, work
, budget
, lock
);
109 gc
->startTask(*tasks
[i
], lock
);
114 ~AutoRunParallelWork() {
115 gHelperThreadLock
.assertOwnedByCurrentThread();
117 for (size_t i
= 0; i
< tasksStarted
; i
++) {
118 gc
->joinTask(*tasks
[i
], lock
);
120 for (size_t i
= tasksStarted
; i
< MaxParallelWorkers
; i
++) {
121 MOZ_ASSERT(tasks
[i
].isNothing());
127 gcstats::PhaseKind phaseKind
;
128 AutoLockHelperThreadState
& lock
;
130 mozilla::Maybe
<Worker
> tasks
[MaxParallelWorkers
];
136 #endif /* gc_ParallelWork_h */