annotate hotspot/src/share/vm/gc/shared/workgroup.hpp @ 35465:34ab60aee787

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