1 | /* |
2 | * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #ifndef SHARE_GC_SHARED_WORKGROUP_HPP |
26 | #define SHARE_GC_SHARED_WORKGROUP_HPP |
27 | |
28 | #include "memory/allocation.hpp" |
29 | #include "runtime/globals.hpp" |
30 | #include "runtime/thread.hpp" |
31 | #include "gc/shared/gcId.hpp" |
32 | #include "logging/log.hpp" |
33 | #include "utilities/debug.hpp" |
34 | #include "utilities/globalDefinitions.hpp" |
35 | |
36 | // Task class hierarchy: |
37 | // AbstractGangTask |
38 | // |
39 | // Gang/Group class hierarchy: |
40 | // AbstractWorkGang |
41 | // WorkGang |
42 | // YieldingFlexibleWorkGang (defined in another file) |
43 | // |
44 | // Worker class hierarchy: |
45 | // AbstractGangWorker (subclass of WorkerThread) |
46 | // GangWorker |
47 | // YieldingFlexibleGangWorker (defined in another file) |
48 | |
49 | // Forward declarations of classes defined here |
50 | |
51 | class AbstractGangWorker; |
52 | class Semaphore; |
53 | class WorkGang; |
54 | |
55 | // An abstract task to be worked on by a gang. |
56 | // You subclass this to supply your own work() method |
57 | class AbstractGangTask { |
58 | const char* _name; |
59 | const uint _gc_id; |
60 | |
61 | public: |
62 | explicit AbstractGangTask(const char* name) : |
63 | _name(name), |
64 | _gc_id(GCId::current_or_undefined()) |
65 | {} |
66 | |
67 | // The abstract work method. |
68 | // The argument tells you which member of the gang you are. |
69 | virtual void work(uint worker_id) = 0; |
70 | |
71 | // Debugging accessor for the name. |
72 | const char* name() const { return _name; } |
73 | const uint gc_id() const { return _gc_id; } |
74 | }; |
75 | |
76 | struct WorkData { |
77 | AbstractGangTask* _task; |
78 | uint _worker_id; |
79 | WorkData(AbstractGangTask* task, uint worker_id) : _task(task), _worker_id(worker_id) {} |
80 | }; |
81 | |
82 | // Interface to handle the synchronization between the coordinator thread and the worker threads, |
83 | // when a task is dispatched out to the worker threads. |
84 | class GangTaskDispatcher : public CHeapObj<mtGC> { |
85 | public: |
86 | virtual ~GangTaskDispatcher() {} |
87 | |
88 | // Coordinator API. |
89 | |
90 | // Distributes the task out to num_workers workers. |
91 | // Returns when the task has been completed by all workers. |
92 | virtual void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) = 0; |
93 | |
94 | // Worker API. |
95 | |
96 | // Waits for a task to become available to the worker. |
97 | // Returns when the worker has been assigned a task. |
98 | virtual WorkData worker_wait_for_task() = 0; |
99 | |
100 | // Signal to the coordinator that the worker is done with the assigned task. |
101 | virtual void worker_done_with_task() = 0; |
102 | }; |
103 | |
104 | // The work gang is the collection of workers to execute tasks. |
105 | // The number of workers run for a task is "_active_workers" |
106 | // while "_total_workers" is the number of available of workers. |
107 | class AbstractWorkGang : public CHeapObj<mtInternal> { |
108 | protected: |
109 | // The array of worker threads for this gang. |
110 | AbstractGangWorker** _workers; |
111 | // The count of the number of workers in the gang. |
112 | uint _total_workers; |
113 | // The currently active workers in this gang. |
114 | uint _active_workers; |
115 | // The count of created workers in the gang. |
116 | uint _created_workers; |
117 | // Printing support. |
118 | const char* _name; |
119 | |
120 | ~AbstractWorkGang() {} |
121 | |
122 | private: |
123 | // Initialize only instance data. |
124 | const bool _are_GC_task_threads; |
125 | const bool _are_ConcurrentGC_threads; |
126 | |
127 | void set_thread(uint worker_id, AbstractGangWorker* worker) { |
128 | _workers[worker_id] = worker; |
129 | } |
130 | |
131 | public: |
132 | AbstractWorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads) : |
133 | _workers(NULL), |
134 | _total_workers(workers), |
135 | _active_workers(UseDynamicNumberOfGCThreads ? 1U : workers), |
136 | _created_workers(0), |
137 | _name(name), |
138 | _are_GC_task_threads(are_GC_task_threads), |
139 | _are_ConcurrentGC_threads(are_ConcurrentGC_threads) |
140 | { } |
141 | |
142 | // Initialize workers in the gang. Return true if initialization succeeded. |
143 | void initialize_workers(); |
144 | |
145 | bool are_GC_task_threads() const { return _are_GC_task_threads; } |
146 | bool are_ConcurrentGC_threads() const { return _are_ConcurrentGC_threads; } |
147 | |
148 | uint total_workers() const { return _total_workers; } |
149 | |
150 | uint created_workers() const { |
151 | return _created_workers; |
152 | } |
153 | |
154 | virtual uint active_workers() const { |
155 | assert(_active_workers <= _total_workers, |
156 | "_active_workers: %u > _total_workers: %u" , _active_workers, _total_workers); |
157 | return _active_workers; |
158 | } |
159 | |
160 | uint update_active_workers(uint v) { |
161 | assert(v <= _total_workers, |
162 | "Trying to set more workers active than there are" ); |
163 | _active_workers = MIN2(v, _total_workers); |
164 | add_workers(false /* exit_on_failure */); |
165 | assert(v != 0, "Trying to set active workers to 0" ); |
166 | log_trace(gc, task)("%s: using %d out of %d workers" , name(), _active_workers, _total_workers); |
167 | return _active_workers; |
168 | } |
169 | |
170 | // Add GC workers as needed. |
171 | void add_workers(bool initializing); |
172 | |
173 | // Add GC workers as needed to reach the specified number of workers. |
174 | void add_workers(uint active_workers, bool initializing); |
175 | |
176 | // Return the Ith worker. |
177 | AbstractGangWorker* worker(uint i) const; |
178 | |
179 | // Base name (without worker id #) of threads. |
180 | const char* group_name() { return name(); } |
181 | |
182 | void threads_do(ThreadClosure* tc) const; |
183 | |
184 | // Create a GC worker and install it into the work gang. |
185 | virtual AbstractGangWorker* install_worker(uint which); |
186 | |
187 | // Debugging. |
188 | const char* name() const { return _name; } |
189 | |
190 | // Printing |
191 | void print_worker_threads_on(outputStream *st) const; |
192 | void print_worker_threads() const { |
193 | print_worker_threads_on(tty); |
194 | } |
195 | |
196 | protected: |
197 | virtual AbstractGangWorker* allocate_worker(uint which) = 0; |
198 | }; |
199 | |
200 | // An class representing a gang of workers. |
201 | class WorkGang: public AbstractWorkGang { |
202 | // To get access to the GangTaskDispatcher instance. |
203 | friend class GangWorker; |
204 | |
205 | GangTaskDispatcher* const _dispatcher; |
206 | GangTaskDispatcher* dispatcher() const { |
207 | return _dispatcher; |
208 | } |
209 | |
210 | public: |
211 | WorkGang(const char* name, |
212 | uint workers, |
213 | bool are_GC_task_threads, |
214 | bool are_ConcurrentGC_threads); |
215 | |
216 | ~WorkGang(); |
217 | |
218 | // Run a task using the current active number of workers, returns when the task is done. |
219 | virtual void run_task(AbstractGangTask* task); |
220 | // Run a task with the given number of workers, returns |
221 | // when the task is done. The number of workers must be at most the number of |
222 | // active workers. Additional workers may be created if an insufficient |
223 | // number currently exists. |
224 | void run_task(AbstractGangTask* task, uint num_workers); |
225 | |
226 | protected: |
227 | virtual AbstractGangWorker* allocate_worker(uint which); |
228 | }; |
229 | |
230 | // Several instances of this class run in parallel as workers for a gang. |
231 | class AbstractGangWorker: public WorkerThread { |
232 | public: |
233 | AbstractGangWorker(AbstractWorkGang* gang, uint id); |
234 | |
235 | // The only real method: run a task for the gang. |
236 | virtual void run(); |
237 | // Predicate for Thread |
238 | virtual bool is_GC_task_thread() const; |
239 | virtual bool is_ConcurrentGC_thread() const; |
240 | // Printing |
241 | void print_on(outputStream* st) const; |
242 | virtual void print() const; |
243 | |
244 | protected: |
245 | AbstractWorkGang* _gang; |
246 | |
247 | virtual void initialize(); |
248 | virtual void loop() = 0; |
249 | |
250 | AbstractWorkGang* gang() const { return _gang; } |
251 | }; |
252 | |
253 | class GangWorker: public AbstractGangWorker { |
254 | public: |
255 | GangWorker(WorkGang* gang, uint id) : AbstractGangWorker(gang, id) {} |
256 | |
257 | protected: |
258 | virtual void loop(); |
259 | |
260 | private: |
261 | WorkData wait_for_task(); |
262 | void run_task(WorkData work); |
263 | void signal_task_done(); |
264 | |
265 | WorkGang* gang() const { return (WorkGang*)_gang; } |
266 | }; |
267 | |
268 | // A class that acts as a synchronisation barrier. Workers enter |
269 | // the barrier and must wait until all other workers have entered |
270 | // before any of them may leave. |
271 | |
272 | class WorkGangBarrierSync : public StackObj { |
273 | protected: |
274 | Monitor _monitor; |
275 | uint _n_workers; |
276 | uint _n_completed; |
277 | bool _should_reset; |
278 | bool _aborted; |
279 | |
280 | Monitor* monitor() { return &_monitor; } |
281 | uint n_workers() { return _n_workers; } |
282 | uint n_completed() { return _n_completed; } |
283 | bool should_reset() { return _should_reset; } |
284 | bool aborted() { return _aborted; } |
285 | |
286 | void zero_completed() { _n_completed = 0; } |
287 | void inc_completed() { _n_completed++; } |
288 | void set_aborted() { _aborted = true; } |
289 | void set_should_reset(bool v) { _should_reset = v; } |
290 | |
291 | public: |
292 | WorkGangBarrierSync(); |
293 | WorkGangBarrierSync(uint n_workers, const char* name); |
294 | |
295 | // Set the number of workers that will use the barrier. |
296 | // Must be called before any of the workers start running. |
297 | void set_n_workers(uint n_workers); |
298 | |
299 | // Enter the barrier. A worker that enters the barrier will |
300 | // not be allowed to leave until all other threads have |
301 | // also entered the barrier or the barrier is aborted. |
302 | // Returns false if the barrier was aborted. |
303 | bool enter(); |
304 | |
305 | // Aborts the barrier and wakes up any threads waiting for |
306 | // the barrier to complete. The barrier will remain in the |
307 | // aborted state until the next call to set_n_workers(). |
308 | void abort(); |
309 | }; |
310 | |
311 | // A class to manage claiming of subtasks within a group of tasks. The |
312 | // subtasks will be identified by integer indices, usually elements of an |
313 | // enumeration type. |
314 | |
315 | class SubTasksDone: public CHeapObj<mtInternal> { |
316 | volatile uint* _tasks; |
317 | uint _n_tasks; |
318 | volatile uint _threads_completed; |
319 | #ifdef ASSERT |
320 | volatile uint _claimed; |
321 | #endif |
322 | |
323 | // Set all tasks to unclaimed. |
324 | void clear(); |
325 | |
326 | public: |
327 | // Initializes "this" to a state in which there are "n" tasks to be |
328 | // processed, none of the which are originally claimed. The number of |
329 | // threads doing the tasks is initialized 1. |
330 | SubTasksDone(uint n); |
331 | |
332 | // True iff the object is in a valid state. |
333 | bool valid(); |
334 | |
335 | // Attempt to claim the task "t", returning true if successful, |
336 | // false if it has already been claimed. The task "t" is required |
337 | // to be within the range of "this". |
338 | bool try_claim_task(uint t); |
339 | |
340 | // The calling thread asserts that it has attempted to claim all the |
341 | // tasks that it will try to claim. Every thread in the parallel task |
342 | // must execute this. (When the last thread does so, the task array is |
343 | // cleared.) |
344 | // |
345 | // n_threads - Number of threads executing the sub-tasks. |
346 | void all_tasks_completed(uint n_threads); |
347 | |
348 | // Destructor. |
349 | ~SubTasksDone(); |
350 | }; |
351 | |
352 | // As above, but for sequential tasks, i.e. instead of claiming |
353 | // sub-tasks from a set (possibly an enumeration), claim sub-tasks |
354 | // in sequential order. This is ideal for claiming dynamically |
355 | // partitioned tasks (like striding in the parallel remembered |
356 | // set scanning). Note that unlike the above class this is |
357 | // a stack object - is there any reason for it not to be? |
358 | |
359 | class SequentialSubTasksDone : public StackObj { |
360 | protected: |
361 | uint _n_tasks; // Total number of tasks available. |
362 | volatile uint _n_claimed; // Number of tasks claimed. |
363 | // _n_threads is used to determine when a sub task is done. |
364 | // See comments on SubTasksDone::_n_threads |
365 | uint _n_threads; // Total number of parallel threads. |
366 | volatile uint _n_completed; // Number of completed threads. |
367 | |
368 | void clear(); |
369 | |
370 | public: |
371 | SequentialSubTasksDone() { |
372 | clear(); |
373 | } |
374 | ~SequentialSubTasksDone() {} |
375 | |
376 | // True iff the object is in a valid state. |
377 | bool valid(); |
378 | |
379 | // number of tasks |
380 | uint n_tasks() const { return _n_tasks; } |
381 | |
382 | // Get/set the number of parallel threads doing the tasks to t. |
383 | // Should be called before the task starts but it is safe |
384 | // to call this once a task is running provided that all |
385 | // threads agree on the number of threads. |
386 | uint n_threads() { return _n_threads; } |
387 | void set_n_threads(uint t) { _n_threads = t; } |
388 | |
389 | // Set the number of tasks to be claimed to t. As above, |
390 | // should be called before the tasks start but it is safe |
391 | // to call this once a task is running provided all threads |
392 | // agree on the number of tasks. |
393 | void set_n_tasks(uint t) { _n_tasks = t; } |
394 | |
395 | // Attempt to claim the next unclaimed task in the sequence, |
396 | // returning true if successful, with t set to the index of the |
397 | // claimed task. Returns false if there are no more unclaimed tasks |
398 | // in the sequence. |
399 | bool try_claim_task(uint& t); |
400 | |
401 | // The calling thread asserts that it has attempted to claim |
402 | // all the tasks it possibly can in the sequence. Every thread |
403 | // claiming tasks must promise call this. Returns true if this |
404 | // is the last thread to complete so that the thread can perform |
405 | // cleanup if necessary. |
406 | bool all_tasks_completed(); |
407 | }; |
408 | |
409 | #endif // SHARE_GC_SHARED_WORKGROUP_HPP |
410 | |