src/share/vm/utilities/workgroup.hpp

Thu, 20 Nov 2008 16:56:09 -0800

author
ysr
date
Thu, 20 Nov 2008 16:56:09 -0800
changeset 888
c96030fff130
parent 777
37f87013dfd8
child 984
fe3d7c11b4b7
permissions
-rw-r--r--

6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa

duke@435 1 /*
duke@435 2 * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
duke@435 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@435 20 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@435 21 * have any questions.
duke@435 22 *
duke@435 23 */
duke@435 24
duke@435 25 // Forward declarations of classes defined here
duke@435 26
duke@435 27 class WorkGang;
duke@435 28 class GangWorker;
duke@435 29 class YieldingFlexibleGangWorker;
duke@435 30 class YieldingFlexibleGangTask;
duke@435 31 class WorkData;
duke@435 32
duke@435 33 // An abstract task to be worked on by a gang.
duke@435 34 // You subclass this to supply your own work() method
duke@435 35 class AbstractGangTask: public CHeapObj {
duke@435 36 public:
duke@435 37 // The abstract work method.
duke@435 38 // The argument tells you which member of the gang you are.
duke@435 39 virtual void work(int i) = 0;
duke@435 40
duke@435 41 // Debugging accessor for the name.
duke@435 42 const char* name() const PRODUCT_RETURN_(return NULL;);
duke@435 43 int counter() { return _counter; }
duke@435 44 void set_counter(int value) { _counter = value; }
duke@435 45 int *address_of_counter() { return &_counter; }
duke@435 46
duke@435 47 // RTTI
duke@435 48 NOT_PRODUCT(virtual bool is_YieldingFlexibleGang_task() const {
duke@435 49 return false;
duke@435 50 })
duke@435 51
duke@435 52 private:
duke@435 53 NOT_PRODUCT(const char* _name;)
duke@435 54 // ??? Should a task have a priority associated with it?
duke@435 55 // ??? Or can the run method adjust priority as needed?
duke@435 56 int _counter;
duke@435 57
duke@435 58 protected:
duke@435 59 // Constructor and desctructor: only construct subclasses.
duke@435 60 AbstractGangTask(const char* name) {
duke@435 61 NOT_PRODUCT(_name = name);
duke@435 62 _counter = 0;
duke@435 63 }
duke@435 64 virtual ~AbstractGangTask() { }
duke@435 65 };
duke@435 66
duke@435 67
duke@435 68 // Class AbstractWorkGang:
duke@435 69 // An abstract class representing a gang of workers.
duke@435 70 // You subclass this to supply an implementation of run_task().
duke@435 71 class AbstractWorkGang: public CHeapObj {
duke@435 72 // Here's the public interface to this class.
duke@435 73 public:
duke@435 74 // Constructor and destructor.
ysr@777 75 AbstractWorkGang(const char* name, bool are_GC_task_threads,
ysr@777 76 bool are_ConcurrentGC_threads);
duke@435 77 ~AbstractWorkGang();
duke@435 78 // Run a task, returns when the task is done (or terminated).
duke@435 79 virtual void run_task(AbstractGangTask* task) = 0;
duke@435 80 // Stop and terminate all workers.
duke@435 81 virtual void stop();
duke@435 82 public:
duke@435 83 // Debugging.
duke@435 84 const char* name() const;
duke@435 85 protected:
duke@435 86 // Initialize only instance data.
ysr@777 87 const bool _are_GC_task_threads;
ysr@777 88 const bool _are_ConcurrentGC_threads;
duke@435 89 // Printing support.
duke@435 90 const char* _name;
duke@435 91 // The monitor which protects these data,
duke@435 92 // and notifies of changes in it.
duke@435 93 Monitor* _monitor;
duke@435 94 // The count of the number of workers in the gang.
duke@435 95 int _total_workers;
duke@435 96 // Whether the workers should terminate.
duke@435 97 bool _terminate;
duke@435 98 // The array of worker threads for this gang.
duke@435 99 // This is only needed for cleaning up.
duke@435 100 GangWorker** _gang_workers;
duke@435 101 // The task for this gang.
duke@435 102 AbstractGangTask* _task;
duke@435 103 // A sequence number for the current task.
duke@435 104 int _sequence_number;
duke@435 105 // The number of started workers.
duke@435 106 int _started_workers;
duke@435 107 // The number of finished workers.
duke@435 108 int _finished_workers;
duke@435 109 public:
duke@435 110 // Accessors for fields
duke@435 111 Monitor* monitor() const {
duke@435 112 return _monitor;
duke@435 113 }
duke@435 114 int total_workers() const {
duke@435 115 return _total_workers;
duke@435 116 }
duke@435 117 bool terminate() const {
duke@435 118 return _terminate;
duke@435 119 }
duke@435 120 GangWorker** gang_workers() const {
duke@435 121 return _gang_workers;
duke@435 122 }
duke@435 123 AbstractGangTask* task() const {
duke@435 124 return _task;
duke@435 125 }
duke@435 126 int sequence_number() const {
duke@435 127 return _sequence_number;
duke@435 128 }
duke@435 129 int started_workers() const {
duke@435 130 return _started_workers;
duke@435 131 }
duke@435 132 int finished_workers() const {
duke@435 133 return _finished_workers;
duke@435 134 }
ysr@777 135 bool are_GC_task_threads() const {
ysr@777 136 return _are_GC_task_threads;
ysr@777 137 }
ysr@777 138 bool are_ConcurrentGC_threads() const {
ysr@777 139 return _are_ConcurrentGC_threads;
duke@435 140 }
duke@435 141 // Predicates.
duke@435 142 bool is_idle() const {
duke@435 143 return (task() == NULL);
duke@435 144 }
duke@435 145 // Return the Ith gang worker.
duke@435 146 GangWorker* gang_worker(int i) const;
duke@435 147
duke@435 148 void threads_do(ThreadClosure* tc) const;
duke@435 149
duke@435 150 // Printing
duke@435 151 void print_worker_threads_on(outputStream *st) const;
duke@435 152 void print_worker_threads() const {
duke@435 153 print_worker_threads_on(tty);
duke@435 154 }
duke@435 155
duke@435 156 protected:
duke@435 157 friend class GangWorker;
duke@435 158 friend class YieldingFlexibleGangWorker;
duke@435 159 // Note activation and deactivation of workers.
duke@435 160 // These methods should only be called with the mutex held.
duke@435 161 void internal_worker_poll(WorkData* data) const;
duke@435 162 void internal_note_start();
duke@435 163 void internal_note_finish();
duke@435 164 };
duke@435 165
duke@435 166 class WorkData: public StackObj {
duke@435 167 // This would be a struct, but I want accessor methods.
duke@435 168 private:
duke@435 169 bool _terminate;
duke@435 170 AbstractGangTask* _task;
duke@435 171 int _sequence_number;
duke@435 172 public:
duke@435 173 // Constructor and destructor
duke@435 174 WorkData() {
duke@435 175 _terminate = false;
duke@435 176 _task = NULL;
duke@435 177 _sequence_number = 0;
duke@435 178 }
duke@435 179 ~WorkData() {
duke@435 180 }
duke@435 181 // Accessors and modifiers
duke@435 182 bool terminate() const { return _terminate; }
duke@435 183 void set_terminate(bool value) { _terminate = value; }
duke@435 184 AbstractGangTask* task() const { return _task; }
duke@435 185 void set_task(AbstractGangTask* value) { _task = value; }
duke@435 186 int sequence_number() const { return _sequence_number; }
duke@435 187 void set_sequence_number(int value) { _sequence_number = value; }
duke@435 188
duke@435 189 YieldingFlexibleGangTask* yf_task() const {
duke@435 190 return (YieldingFlexibleGangTask*)_task;
duke@435 191 }
duke@435 192 };
duke@435 193
duke@435 194 // Class WorkGang:
duke@435 195 class WorkGang: public AbstractWorkGang {
duke@435 196 public:
duke@435 197 // Constructor
ysr@777 198 WorkGang(const char* name, int workers,
ysr@777 199 bool are_GC_task_threads, bool are_ConcurrentGC_threads);
duke@435 200 // Run a task, returns when the task is done (or terminated).
duke@435 201 virtual void run_task(AbstractGangTask* task);
duke@435 202 };
duke@435 203
duke@435 204 // Class GangWorker:
duke@435 205 // Several instances of this class run in parallel as workers for a gang.
duke@435 206 class GangWorker: public WorkerThread {
duke@435 207 public:
duke@435 208 // Constructors and destructor.
duke@435 209 GangWorker(AbstractWorkGang* gang, uint id);
duke@435 210
duke@435 211 // The only real method: run a task for the gang.
duke@435 212 virtual void run();
duke@435 213 // Predicate for Thread
duke@435 214 virtual bool is_GC_task_thread() const;
ysr@777 215 virtual bool is_ConcurrentGC_thread() const;
duke@435 216 // Printing
duke@435 217 void print_on(outputStream* st) const;
duke@435 218 virtual void print() const { print_on(tty); }
duke@435 219 protected:
duke@435 220 AbstractWorkGang* _gang;
duke@435 221
duke@435 222 virtual void initialize();
duke@435 223 virtual void loop();
duke@435 224
duke@435 225 public:
duke@435 226 AbstractWorkGang* gang() const { return _gang; }
duke@435 227 };
duke@435 228
duke@435 229 // A class that acts as a synchronisation barrier. Workers enter
duke@435 230 // the barrier and must wait until all other workers have entered
duke@435 231 // before any of them may leave.
duke@435 232
duke@435 233 class WorkGangBarrierSync : public StackObj {
duke@435 234 protected:
duke@435 235 Monitor _monitor;
duke@435 236 int _n_workers;
duke@435 237 int _n_completed;
ysr@777 238 bool _should_reset;
duke@435 239
ysr@777 240 Monitor* monitor() { return &_monitor; }
ysr@777 241 int n_workers() { return _n_workers; }
ysr@777 242 int n_completed() { return _n_completed; }
ysr@777 243 bool should_reset() { return _should_reset; }
duke@435 244
ysr@777 245 void zero_completed() { _n_completed = 0; }
ysr@777 246 void inc_completed() { _n_completed++; }
ysr@777 247
ysr@777 248 void set_should_reset(bool v) { _should_reset = v; }
duke@435 249
duke@435 250 public:
duke@435 251 WorkGangBarrierSync();
duke@435 252 WorkGangBarrierSync(int n_workers, const char* name);
duke@435 253
duke@435 254 // Set the number of workers that will use the barrier.
duke@435 255 // Must be called before any of the workers start running.
duke@435 256 void set_n_workers(int n_workers);
duke@435 257
duke@435 258 // Enter the barrier. A worker that enters the barrier will
duke@435 259 // not be allowed to leave until all other threads have
duke@435 260 // also entered the barrier.
duke@435 261 void enter();
duke@435 262 };
duke@435 263
duke@435 264 // A class to manage claiming of subtasks within a group of tasks. The
duke@435 265 // subtasks will be identified by integer indices, usually elements of an
duke@435 266 // enumeration type.
duke@435 267
duke@435 268 class SubTasksDone: public CHeapObj {
duke@435 269 jint* _tasks;
duke@435 270 int _n_tasks;
duke@435 271 int _n_threads;
duke@435 272 jint _threads_completed;
duke@435 273 #ifdef ASSERT
duke@435 274 jint _claimed;
duke@435 275 #endif
duke@435 276
duke@435 277 // Set all tasks to unclaimed.
duke@435 278 void clear();
duke@435 279
duke@435 280 public:
duke@435 281 // Initializes "this" to a state in which there are "n" tasks to be
duke@435 282 // processed, none of the which are originally claimed. The number of
duke@435 283 // threads doing the tasks is initialized 1.
duke@435 284 SubTasksDone(int n);
duke@435 285
duke@435 286 // True iff the object is in a valid state.
duke@435 287 bool valid();
duke@435 288
duke@435 289 // Set the number of parallel threads doing the tasks to "t". Can only
duke@435 290 // be called before tasks start or after they are complete.
duke@435 291 void set_par_threads(int t);
duke@435 292
duke@435 293 // Returns "false" if the task "t" is unclaimed, and ensures that task is
duke@435 294 // claimed. The task "t" is required to be within the range of "this".
duke@435 295 bool is_task_claimed(int t);
duke@435 296
duke@435 297 // The calling thread asserts that it has attempted to claim all the
duke@435 298 // tasks that it will try to claim. Every thread in the parallel task
duke@435 299 // must execute this. (When the last thread does so, the task array is
duke@435 300 // cleared.)
duke@435 301 void all_tasks_completed();
duke@435 302
duke@435 303 // Destructor.
duke@435 304 ~SubTasksDone();
duke@435 305 };
duke@435 306
duke@435 307 // As above, but for sequential tasks, i.e. instead of claiming
duke@435 308 // sub-tasks from a set (possibly an enumeration), claim sub-tasks
duke@435 309 // in sequential order. This is ideal for claiming dynamically
duke@435 310 // partitioned tasks (like striding in the parallel remembered
duke@435 311 // set scanning). Note that unlike the above class this is
duke@435 312 // a stack object - is there any reason for it not to be?
duke@435 313
duke@435 314 class SequentialSubTasksDone : public StackObj {
duke@435 315 protected:
duke@435 316 jint _n_tasks; // Total number of tasks available.
duke@435 317 jint _n_claimed; // Number of tasks claimed.
duke@435 318 jint _n_threads; // Total number of parallel threads.
duke@435 319 jint _n_completed; // Number of completed threads.
duke@435 320
duke@435 321 void clear();
duke@435 322
duke@435 323 public:
duke@435 324 SequentialSubTasksDone() { clear(); }
duke@435 325 ~SequentialSubTasksDone() {}
duke@435 326
duke@435 327 // True iff the object is in a valid state.
duke@435 328 bool valid();
duke@435 329
duke@435 330 // number of tasks
duke@435 331 jint n_tasks() const { return _n_tasks; }
duke@435 332
duke@435 333 // Set the number of parallel threads doing the tasks to t.
duke@435 334 // Should be called before the task starts but it is safe
duke@435 335 // to call this once a task is running provided that all
duke@435 336 // threads agree on the number of threads.
duke@435 337 void set_par_threads(int t) { _n_threads = t; }
duke@435 338
duke@435 339 // Set the number of tasks to be claimed to t. As above,
duke@435 340 // should be called before the tasks start but it is safe
duke@435 341 // to call this once a task is running provided all threads
duke@435 342 // agree on the number of tasks.
duke@435 343 void set_n_tasks(int t) { _n_tasks = t; }
duke@435 344
duke@435 345 // Returns false if the next task in the sequence is unclaimed,
duke@435 346 // and ensures that it is claimed. Will set t to be the index
duke@435 347 // of the claimed task in the sequence. Will return true if
duke@435 348 // the task cannot be claimed and there are none left to claim.
duke@435 349 bool is_task_claimed(int& t);
duke@435 350
duke@435 351 // The calling thread asserts that it has attempted to claim
duke@435 352 // all the tasks it possibly can in the sequence. Every thread
duke@435 353 // claiming tasks must promise call this. Returns true if this
duke@435 354 // is the last thread to complete so that the thread can perform
duke@435 355 // cleanup if necessary.
duke@435 356 bool all_tasks_completed();
duke@435 357 };
ysr@777 358
ysr@777 359 // Represents a set of free small integer ids.
ysr@777 360 class FreeIdSet {
ysr@777 361 enum {
ysr@777 362 end_of_list = -1,
ysr@777 363 claimed = -2
ysr@777 364 };
ysr@777 365
ysr@777 366 int _sz;
ysr@777 367 Monitor* _mon;
ysr@777 368
ysr@777 369 int* _ids;
ysr@777 370 int _hd;
ysr@777 371 int _waiters;
ysr@777 372 int _claimed;
ysr@777 373
ysr@777 374 static bool _safepoint;
ysr@777 375 typedef FreeIdSet* FreeIdSetPtr;
ysr@777 376 static const int NSets = 10;
ysr@777 377 static FreeIdSetPtr _sets[NSets];
ysr@777 378 static bool _stat_init;
ysr@777 379 int _index;
ysr@777 380
ysr@777 381 public:
ysr@777 382 FreeIdSet(int sz, Monitor* mon);
ysr@777 383 ~FreeIdSet();
ysr@777 384
ysr@777 385 static void set_safepoint(bool b);
ysr@777 386
ysr@777 387 // Attempt to claim the given id permanently. Returns "true" iff
ysr@777 388 // successful.
ysr@777 389 bool claim_perm_id(int i);
ysr@777 390
ysr@777 391 // Returns an unclaimed parallel id (waiting for one to be released if
ysr@777 392 // necessary). Returns "-1" if a GC wakes up a wait for an id.
ysr@777 393 int claim_par_id();
ysr@777 394
ysr@777 395 void release_par_id(int id);
ysr@777 396 };

mercurial