1 /* 2 * Copyright (c) 2002, 2021, 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 "metaprogramming/enableIf.hpp" 30 #include "metaprogramming/logical.hpp" 31 #include "runtime/globals.hpp" 32 #include "runtime/nonJavaThread.hpp" 33 #include "runtime/thread.hpp" 34 #include "gc/shared/gcId.hpp" 35 #include "logging/log.hpp" 36 #include "utilities/debug.hpp" 37 #include "utilities/globalDefinitions.hpp" 38 39 // Task class hierarchy: 40 // AbstractGangTask 41 // 42 // Gang/Group class hierarchy: 43 // WorkGang 44 // 45 // Worker class hierarchy: 46 // GangWorker (subclass of WorkerThread) 47 48 // Forward declarations of classes defined here 49 50 class GangWorker; 51 class Semaphore; 52 class ThreadClosure; 53 class GangTaskDispatcher; 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 : public CHeapObj<mtInternal> { 58 const char* _name; 59 const uint _gc_id; 60 61 public: AbstractGangTask(const char * name)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. name() const72 const char* name() const { return _name; } gc_id() const73 const uint gc_id() const { return _gc_id; } 74 }; 75 76 struct WorkData { 77 AbstractGangTask* _task; 78 uint _worker_id; WorkDataWorkData79 WorkData(AbstractGangTask* task, uint worker_id) : _task(task), _worker_id(worker_id) {} 80 }; 81 82 // The work gang is the collection of workers to execute tasks. 83 // The number of workers run for a task is "_active_workers" 84 // while "_total_workers" is the number of available workers. 85 class WorkGang : public CHeapObj<mtInternal> { 86 // The array of worker threads for this gang. 87 GangWorker** _workers; 88 // The count of the number of workers in the gang. 89 uint _total_workers; 90 // The currently active workers in this gang. 91 uint _active_workers; 92 // The count of created workers in the gang. 93 uint _created_workers; 94 // Printing support. 95 const char* _name; 96 97 // Initialize only instance data. 98 const bool _are_GC_task_threads; 99 const bool _are_ConcurrentGC_threads; 100 101 // To get access to the GangTaskDispatcher instance. 102 friend class GangWorker; 103 GangTaskDispatcher* const _dispatcher; 104 dispatcher() const105 GangTaskDispatcher* dispatcher() const { return _dispatcher; } 106 set_thread(uint worker_id,GangWorker * worker)107 void set_thread(uint worker_id, GangWorker* worker) { 108 _workers[worker_id] = worker; 109 } 110 111 // Add GC workers when _created_workers < _active_workers; otherwise, no-op. 112 // If there's no memory/thread allocation failure, _created_worker is 113 // adjusted to match _active_workers (_created_worker == _active_workers). 114 void add_workers(bool initializing); 115 116 GangWorker* allocate_worker(uint which); 117 118 public: 119 WorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads); 120 121 ~WorkGang(); 122 123 // Initialize workers in the gang. Return true if initialization succeeded. 124 void initialize_workers(); 125 are_GC_task_threads() const126 bool are_GC_task_threads() const { return _are_GC_task_threads; } are_ConcurrentGC_threads() const127 bool are_ConcurrentGC_threads() const { return _are_ConcurrentGC_threads; } 128 total_workers() const129 uint total_workers() const { return _total_workers; } 130 created_workers() const131 uint created_workers() const { 132 return _created_workers; 133 } 134 active_workers() const135 uint active_workers() const { 136 assert(_active_workers != 0, "zero active workers"); 137 assert(_active_workers <= _total_workers, 138 "_active_workers: %u > _total_workers: %u", _active_workers, _total_workers); 139 return _active_workers; 140 } 141 update_active_workers(uint v)142 uint update_active_workers(uint v) { 143 assert(v <= _total_workers, 144 "Trying to set more workers active than there are"); 145 assert(v != 0, "Trying to set active workers to 0"); 146 _active_workers = v; 147 add_workers(false /* initializing */); 148 log_trace(gc, task)("%s: using %d out of %d workers", name(), _active_workers, _total_workers); 149 return _active_workers; 150 } 151 152 // Return the Ith worker. 153 GangWorker* worker(uint i) const; 154 155 // Base name (without worker id #) of threads. group_name()156 const char* group_name() { return name(); } 157 158 void threads_do(ThreadClosure* tc) const; 159 160 // Create a GC worker and install it into the work gang. 161 virtual GangWorker* install_worker(uint which); 162 163 // Debugging. name() const164 const char* name() const { return _name; } 165 166 // Run a task using the current active number of workers, returns when the task is done. 167 void run_task(AbstractGangTask* task); 168 169 // Run a task with the given number of workers, returns 170 // when the task is done. The number of workers must be at most the number of 171 // active workers. Additional workers may be created if an insufficient 172 // number currently exists. If the add_foreground_work flag is true, the current thread 173 // is used to run the task too. 174 void run_task(AbstractGangTask* task, uint num_workers, bool add_foreground_work = false); 175 }; 176 177 // Temporarily try to set the number of active workers. 178 // It's not guaranteed that it succeeds, and users need to 179 // query the number of active workers. 180 class WithUpdatedActiveWorkers : public StackObj { 181 private: 182 WorkGang* const _gang; 183 const uint _old_active_workers; 184 185 public: WithUpdatedActiveWorkers(WorkGang * gang,uint requested_num_workers)186 WithUpdatedActiveWorkers(WorkGang* gang, uint requested_num_workers) : 187 _gang(gang), 188 _old_active_workers(gang->active_workers()) { 189 uint capped_num_workers = MIN2(requested_num_workers, gang->total_workers()); 190 gang->update_active_workers(capped_num_workers); 191 } 192 ~WithUpdatedActiveWorkers()193 ~WithUpdatedActiveWorkers() { 194 _gang->update_active_workers(_old_active_workers); 195 } 196 }; 197 198 // Several instances of this class run in parallel as workers for a gang. 199 class GangWorker: public WorkerThread { 200 private: 201 WorkGang* _gang; 202 203 void initialize(); 204 void loop(); 205 gang() const206 WorkGang* gang() const { return _gang; } 207 208 WorkData wait_for_task(); 209 void run_task(WorkData work); 210 void signal_task_done(); 211 212 protected: 213 // The only real method: run a task for the gang. 214 void run() override; 215 216 public: 217 GangWorker(WorkGang* gang, uint id); 218 219 // Predicate for Thread is_GC_task_thread() const220 bool is_GC_task_thread() const override { return gang()->are_GC_task_threads(); } is_ConcurrentGC_thread() const221 bool is_ConcurrentGC_thread() const override { return gang()->are_ConcurrentGC_threads(); } 222 }; 223 224 // A class that acts as a synchronisation barrier. Workers enter 225 // the barrier and must wait until all other workers have entered 226 // before any of them may leave. 227 228 class WorkGangBarrierSync : public StackObj { 229 protected: 230 Monitor _monitor; 231 uint _n_workers; 232 uint _n_completed; 233 bool _should_reset; 234 bool _aborted; 235 monitor()236 Monitor* monitor() { return &_monitor; } n_workers()237 uint n_workers() { return _n_workers; } n_completed()238 uint n_completed() { return _n_completed; } should_reset()239 bool should_reset() { return _should_reset; } aborted()240 bool aborted() { return _aborted; } 241 zero_completed()242 void zero_completed() { _n_completed = 0; } inc_completed()243 void inc_completed() { _n_completed++; } set_aborted()244 void set_aborted() { _aborted = true; } set_should_reset(bool v)245 void set_should_reset(bool v) { _should_reset = v; } 246 247 public: 248 WorkGangBarrierSync(); 249 WorkGangBarrierSync(uint n_workers, const char* name); 250 251 // Set the number of workers that will use the barrier. 252 // Must be called before any of the workers start running. 253 void set_n_workers(uint n_workers); 254 255 // Enter the barrier. A worker that enters the barrier will 256 // not be allowed to leave until all other threads have 257 // also entered the barrier or the barrier is aborted. 258 // Returns false if the barrier was aborted. 259 bool enter(); 260 261 // Aborts the barrier and wakes up any threads waiting for 262 // the barrier to complete. The barrier will remain in the 263 // aborted state until the next call to set_n_workers(). 264 void abort(); 265 }; 266 267 // A class to manage claiming of subtasks within a group of tasks. The 268 // subtasks will be identified by integer indices, usually elements of an 269 // enumeration type. 270 271 class SubTasksDone: public CHeapObj<mtInternal> { 272 volatile bool* _tasks; 273 uint _n_tasks; 274 275 // make sure verification logic is run exactly once to avoid duplicate assertion failures 276 DEBUG_ONLY(volatile bool _verification_done = false;) 277 void all_tasks_claimed_impl(uint skipped[], size_t skipped_size) NOT_DEBUG_RETURN; 278 279 NONCOPYABLE(SubTasksDone); 280 281 public: 282 // Initializes "this" to a state in which there are "n" tasks to be 283 // processed, none of the which are originally claimed. 284 SubTasksDone(uint n); 285 286 // Attempt to claim the task "t", returning true if successful, 287 // false if it has already been claimed. The task "t" is required 288 // to be within the range of "this". 289 bool try_claim_task(uint t); 290 291 // The calling thread asserts that it has attempted to claim all the tasks 292 // that it will try to claim. Tasks that are meant to be skipped must be 293 // explicitly passed as extra arguments. Every thread in the parallel task 294 // must execute this. 295 template<typename T0, typename... Ts, 296 ENABLE_IF(Conjunction<std::is_same<T0, Ts>...>::value)> all_tasks_claimed(T0 first_skipped,Ts...more_skipped)297 void all_tasks_claimed(T0 first_skipped, Ts... more_skipped) { 298 static_assert(std::is_convertible<T0, uint>::value, "not convertible"); 299 uint skipped[] = { static_cast<uint>(first_skipped), static_cast<uint>(more_skipped)... }; 300 all_tasks_claimed_impl(skipped, ARRAY_SIZE(skipped)); 301 } 302 // if there are no skipped tasks. all_tasks_claimed()303 void all_tasks_claimed() { 304 all_tasks_claimed_impl(nullptr, 0); 305 } 306 307 // Destructor. 308 ~SubTasksDone(); 309 }; 310 311 // As above, but for sequential tasks, i.e. instead of claiming 312 // sub-tasks from a set (possibly an enumeration), claim sub-tasks 313 // in sequential order. This is ideal for claiming dynamically 314 // partitioned tasks (like striding in the parallel remembered 315 // set scanning). 316 317 class SequentialSubTasksDone : public CHeapObj<mtInternal> { 318 319 uint _num_tasks; // Total number of tasks available. 320 volatile uint _num_claimed; // Number of tasks claimed. 321 322 NONCOPYABLE(SequentialSubTasksDone); 323 324 public: SequentialSubTasksDone(uint num_tasks)325 SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { } ~SequentialSubTasksDone()326 ~SequentialSubTasksDone() { 327 // Claiming may try to claim more tasks than there are. 328 assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks); 329 } 330 331 // Attempt to claim the next unclaimed task in the sequence, 332 // returning true if successful, with t set to the index of the 333 // claimed task. Returns false if there are no more unclaimed tasks 334 // in the sequence. In this case t is undefined. 335 bool try_claim_task(uint& t); 336 }; 337 338 #endif // SHARE_GC_SHARED_WORKGROUP_HPP 339