1 /* 2 * Copyright (c) 2002, 2020, 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 ThreadClosure; 54 class WorkGang; 55 class GangTaskDispatcher; 56 57 // An abstract task to be worked on by a gang. 58 // You subclass this to supply your own work() method 59 class AbstractGangTask { 60 const char* _name; 61 const uint _gc_id; 62 63 public: 64 explicit AbstractGangTask(const char* name) : 65 _name(name), 66 _gc_id(GCId::current_or_undefined()) 67 {} 68 69 // The abstract work method. 70 // The argument tells you which member of the gang you are. 71 virtual void work(uint worker_id) = 0; 72 73 // Debugging accessor for the name. 74 const char* name() const { return _name; } 75 const uint gc_id() const { return _gc_id; } 76 }; 77 78 struct WorkData { 79 AbstractGangTask* _task; 80 uint _worker_id; 81 WorkData(AbstractGangTask* task, uint worker_id) : _task(task), _worker_id(worker_id) {} 82 }; 83 84 // The work gang is the collection of workers to execute tasks. 85 // The number of workers run for a task is "_active_workers" 86 // while "_total_workers" is the number of available of workers. 87 class AbstractWorkGang : public CHeapObj<mtInternal> { 88 protected: 89 // The array of worker threads for this gang. 90 AbstractGangWorker** _workers; 91 // The count of the number of workers in the gang. 92 uint _total_workers; 93 // The currently active workers in this gang. 94 uint _active_workers; 95 // The count of created workers in the gang. 96 uint _created_workers; 97 // Printing support. 98 const char* _name; 99 100 ~AbstractWorkGang() {} 101 102 private: 103 // Initialize only instance data. 104 const bool _are_GC_task_threads; 105 const bool _are_ConcurrentGC_threads; 106 107 void set_thread(uint worker_id, AbstractGangWorker* worker) { 108 _workers[worker_id] = worker; 109 } 110 111 public: 112 AbstractWorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads) : 113 _workers(NULL), 114 _total_workers(workers), 115 _active_workers(UseDynamicNumberOfGCThreads ? 1U : workers), 116 _created_workers(0), 117 _name(name), 118 _are_GC_task_threads(are_GC_task_threads), 119 _are_ConcurrentGC_threads(are_ConcurrentGC_threads) 120 { } 121 122 // Initialize workers in the gang. Return true if initialization succeeded. 123 void initialize_workers(); 124 125 bool are_GC_task_threads() const { return _are_GC_task_threads; } 126 bool are_ConcurrentGC_threads() const { return _are_ConcurrentGC_threads; } 127 128 uint total_workers() const { return _total_workers; } 129 130 uint created_workers() const { 131 return _created_workers; 132 } 133 134 virtual uint active_workers() const { 135 assert(_active_workers <= _total_workers, 136 "_active_workers: %u > _total_workers: %u", _active_workers, _total_workers); 137 return _active_workers; 138 } 139 140 uint update_active_workers(uint v) { 141 assert(v <= _total_workers, 142 "Trying to set more workers active than there are"); 143 _active_workers = MIN2(v, _total_workers); 144 add_workers(false /* exit_on_failure */); 145 assert(v != 0, "Trying to set active workers to 0"); 146 log_trace(gc, task)("%s: using %d out of %d workers", name(), _active_workers, _total_workers); 147 return _active_workers; 148 } 149 150 // Add GC workers as needed. 151 void add_workers(bool initializing); 152 153 // Add GC workers as needed to reach the specified number of workers. 154 void add_workers(uint active_workers, bool initializing); 155 156 // Return the Ith worker. 157 AbstractGangWorker* worker(uint i) const; 158 159 // Base name (without worker id #) of threads. 160 const char* group_name() { return name(); } 161 162 void threads_do(ThreadClosure* tc) const; 163 164 // Create a GC worker and install it into the work gang. 165 virtual AbstractGangWorker* install_worker(uint which); 166 167 // Debugging. 168 const char* name() const { return _name; } 169 170 protected: 171 virtual AbstractGangWorker* allocate_worker(uint which) = 0; 172 }; 173 174 // An class representing a gang of workers. 175 class WorkGang: public AbstractWorkGang { 176 // To get access to the GangTaskDispatcher instance. 177 friend class GangWorker; 178 179 GangTaskDispatcher* const _dispatcher; 180 GangTaskDispatcher* dispatcher() const { 181 return _dispatcher; 182 } 183 184 public: 185 WorkGang(const char* name, 186 uint workers, 187 bool are_GC_task_threads, 188 bool are_ConcurrentGC_threads); 189 190 ~WorkGang(); 191 192 // Run a task using the current active number of workers, returns when the task is done. 193 virtual void run_task(AbstractGangTask* task); 194 // Run a task with the given number of workers, returns 195 // when the task is done. The number of workers must be at most the number of 196 // active workers. Additional workers may be created if an insufficient 197 // number currently exists. If the add_foreground_work flag is true, the current thread 198 // is used to run the task too. 199 void run_task(AbstractGangTask* task, uint num_workers, bool add_foreground_work = false); 200 201 protected: 202 virtual AbstractGangWorker* allocate_worker(uint which); 203 }; 204 205 // Several instances of this class run in parallel as workers for a gang. 206 class AbstractGangWorker: public WorkerThread { 207 public: 208 AbstractGangWorker(AbstractWorkGang* gang, uint id); 209 210 // The only real method: run a task for the gang. 211 virtual void run(); 212 // Predicate for Thread 213 virtual bool is_GC_task_thread() const; 214 virtual bool is_ConcurrentGC_thread() const; 215 // Printing 216 void print_on(outputStream* st) const; 217 virtual void print() const; 218 219 protected: 220 AbstractWorkGang* _gang; 221 222 virtual void initialize(); 223 virtual void loop() = 0; 224 225 AbstractWorkGang* gang() const { return _gang; } 226 }; 227 228 class GangWorker: public AbstractGangWorker { 229 public: 230 GangWorker(WorkGang* gang, uint id) : AbstractGangWorker(gang, id) {} 231 232 protected: 233 virtual void loop(); 234 235 private: 236 WorkData wait_for_task(); 237 void run_task(WorkData work); 238 void signal_task_done(); 239 240 WorkGang* gang() const { return (WorkGang*)_gang; } 241 }; 242 243 // A class that acts as a synchronisation barrier. Workers enter 244 // the barrier and must wait until all other workers have entered 245 // before any of them may leave. 246 247 class WorkGangBarrierSync : public StackObj { 248 protected: 249 Monitor _monitor; 250 uint _n_workers; 251 uint _n_completed; 252 bool _should_reset; 253 bool _aborted; 254 255 Monitor* monitor() { return &_monitor; } 256 uint n_workers() { return _n_workers; } 257 uint n_completed() { return _n_completed; } 258 bool should_reset() { return _should_reset; } 259 bool aborted() { return _aborted; } 260 261 void zero_completed() { _n_completed = 0; } 262 void inc_completed() { _n_completed++; } 263 void set_aborted() { _aborted = true; } 264 void set_should_reset(bool v) { _should_reset = v; } 265 266 public: 267 WorkGangBarrierSync(); 268 WorkGangBarrierSync(uint n_workers, const char* name); 269 270 // Set the number of workers that will use the barrier. 271 // Must be called before any of the workers start running. 272 void set_n_workers(uint n_workers); 273 274 // Enter the barrier. A worker that enters the barrier will 275 // not be allowed to leave until all other threads have 276 // also entered the barrier or the barrier is aborted. 277 // Returns false if the barrier was aborted. 278 bool enter(); 279 280 // Aborts the barrier and wakes up any threads waiting for 281 // the barrier to complete. The barrier will remain in the 282 // aborted state until the next call to set_n_workers(). 283 void abort(); 284 }; 285 286 // A class to manage claiming of subtasks within a group of tasks. The 287 // subtasks will be identified by integer indices, usually elements of an 288 // enumeration type. 289 290 class SubTasksDone: public CHeapObj<mtInternal> { 291 volatile uint* _tasks; 292 uint _n_tasks; 293 volatile uint _threads_completed; 294 #ifdef ASSERT 295 volatile uint _claimed; 296 #endif 297 298 // Set all tasks to unclaimed. 299 void clear(); 300 301 NONCOPYABLE(SubTasksDone); 302 303 public: 304 // Initializes "this" to a state in which there are "n" tasks to be 305 // processed, none of the which are originally claimed. The number of 306 // threads doing the tasks is initialized 1. 307 SubTasksDone(uint n); 308 309 // True iff the object is in a valid state. 310 bool valid(); 311 312 // Attempt to claim the task "t", returning true if successful, 313 // false if it has already been claimed. The task "t" is required 314 // to be within the range of "this". 315 bool try_claim_task(uint t); 316 317 // The calling thread asserts that it has attempted to claim all the 318 // tasks that it will try to claim. Every thread in the parallel task 319 // must execute this. (When the last thread does so, the task array is 320 // cleared.) 321 // 322 // n_threads - Number of threads executing the sub-tasks. 323 void all_tasks_completed(uint n_threads); 324 325 // Destructor. 326 ~SubTasksDone(); 327 }; 328 329 // As above, but for sequential tasks, i.e. instead of claiming 330 // sub-tasks from a set (possibly an enumeration), claim sub-tasks 331 // in sequential order. This is ideal for claiming dynamically 332 // partitioned tasks (like striding in the parallel remembered 333 // set scanning). Note that unlike the above class this is 334 // a stack object - is there any reason for it not to be? 335 336 class SequentialSubTasksDone : public StackObj { 337 protected: 338 uint _n_tasks; // Total number of tasks available. 339 volatile uint _n_claimed; // Number of tasks claimed. 340 // _n_threads is used to determine when a sub task is done. 341 // See comments on SubTasksDone::_n_threads 342 uint _n_threads; // Total number of parallel threads. 343 volatile uint _n_completed; // Number of completed threads. 344 345 void clear(); 346 347 public: 348 SequentialSubTasksDone() { 349 clear(); 350 } 351 ~SequentialSubTasksDone() {} 352 353 // True iff the object is in a valid state. 354 bool valid(); 355 356 // number of tasks 357 uint n_tasks() const { return _n_tasks; } 358 359 // Get/set the number of parallel threads doing the tasks to t. 360 // Should be called before the task starts but it is safe 361 // to call this once a task is running provided that all 362 // threads agree on the number of threads. 363 uint n_threads() { return _n_threads; } 364 void set_n_threads(uint t) { _n_threads = t; } 365 366 // Set the number of tasks to be claimed to t. As above, 367 // should be called before the tasks start but it is safe 368 // to call this once a task is running provided all threads 369 // agree on the number of tasks. 370 void set_n_tasks(uint t) { _n_tasks = t; } 371 372 // Attempt to claim the next unclaimed task in the sequence, 373 // returning true if successful, with t set to the index of the 374 // claimed task. Returns false if there are no more unclaimed tasks 375 // in the sequence. 376 bool try_claim_task(uint& t); 377 378 // The calling thread asserts that it has attempted to claim 379 // all the tasks it possibly can in the sequence. Every thread 380 // claiming tasks must promise call this. Returns true if this 381 // is the last thread to complete so that the thread can perform 382 // cleanup if necessary. 383 bool all_tasks_completed(); 384 }; 385 386 #endif // SHARE_GC_SHARED_WORKGROUP_HPP