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