| 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 | |