< prev index next >

src/share/vm/gc/shared/workgroup.cpp

Print this page




  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 #include "precompiled.hpp"
  26 #include "gc/shared/workgroup.hpp"
  27 #include "memory/allocation.hpp"
  28 #include "memory/allocation.inline.hpp"
  29 #include "runtime/atomic.inline.hpp"
  30 #include "runtime/os.hpp"

  31 #include "runtime/thread.inline.hpp"
  32 #include "utilities/semaphore.hpp"
  33 
  34 // Definitions of WorkGang methods.
  35 
  36 // The current implementation will exit if the allocation
  37 // of any worker fails.  Still, return a boolean so that
  38 // a future implementation can possibly do a partial
  39 // initialization of the workers and report such to the
  40 // caller.
  41 bool AbstractWorkGang::initialize_workers() {
  42 
  43   if (TraceWorkGang) {
  44     tty->print_cr("Constructing work gang %s with %d threads",
  45                   name(),
  46                   total_workers());
  47   }
  48   _workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal);
  49   if (_workers == NULL) {
  50     vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
  51     return false;
  52   }


  81   assert(result != NULL, "Indexing to null worker");
  82   return result;
  83 }
  84 
  85 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
  86   uint workers = total_workers();
  87   for (uint i = 0; i < workers; i++) {
  88     worker(i)->print_on(st);
  89     st->cr();
  90   }
  91 }
  92 
  93 void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
  94   assert(tc != NULL, "Null ThreadClosure");
  95   uint workers = total_workers();
  96   for (uint i = 0; i < workers; i++) {
  97     tc->do_thread(worker(i));
  98   }
  99 }
 100 
 101 #if IMPLEMENTS_SEMAPHORE_CLASS
 102 
 103 // WorkGang dispatcher implemented with semaphores.
 104 //
 105 // Semaphores don't require the worker threads to re-claim the lock when they wake up.
 106 // This helps lowering the latency when starting and stopping the worker threads.
 107 class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
 108   // The task currently being dispatched to the GangWorkers.
 109   AbstractGangTask* _task;
 110 
 111   volatile uint _started;
 112   volatile uint _not_finished;
 113 
 114   // Semaphore used to start the GangWorkers.
 115   Semaphore* _start_semaphore;
 116   // Semaphore used to notify the coordinator that all workers are done.
 117   Semaphore* _end_semaphore;
 118 
 119 public:
 120   SemaphoreGangTaskDispatcher(uint workers) :
 121       _task(NULL),
 122       _started(0),
 123       _not_finished(0),
 124       // Limit the semaphore value to the number of workers.
 125       _start_semaphore(new Semaphore(0, workers)),
 126       _end_semaphore(new Semaphore(0, workers))
 127 { }
 128 
 129   ~SemaphoreGangTaskDispatcher() {
 130     delete _start_semaphore;
 131     delete _end_semaphore;
 132   }
 133 
 134   void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
 135     // No workers are allowed to read the state variables until they have been signaled.
 136     _task         = task;
 137     _not_finished = num_workers;
 138 
 139     // Dispatch 'num_workers' number of tasks.
 140     _start_semaphore->signal(num_workers);
 141 
 142     // Wait for the last worker to signal the coordinator.
 143     _end_semaphore->wait();
 144 
 145     // No workers are allowed to read the state variables after the coordinator has been signaled.
 146     _task         = NULL;


 154 
 155     uint num_started = (uint) Atomic::add(1, (volatile jint*)&_started);
 156 
 157     // Subtract one to get a zero-indexed worker id.
 158     uint worker_id = num_started - 1;
 159 
 160     return WorkData(_task, worker_id);
 161   }
 162 
 163   void worker_done_with_task() {
 164     // Mark that the worker is done with the task.
 165     // The worker is not allowed to read the state variables after this line.
 166     uint not_finished = (uint) Atomic::add(-1, (volatile jint*)&_not_finished);
 167 
 168     // The last worker signals to the coordinator that all work is completed.
 169     if (not_finished == 0) {
 170       _end_semaphore->signal();
 171     }
 172   }
 173 };
 174 #endif // IMPLEMENTS_SEMAPHORE_CLASS
 175 
 176 class MutexGangTaskDispatcher : public GangTaskDispatcher {
 177   AbstractGangTask* _task;
 178 
 179   volatile uint _started;
 180   volatile uint _finished;
 181   volatile uint _num_workers;
 182 
 183   Monitor* _monitor;
 184 
 185  public:
 186   MutexGangTaskDispatcher()
 187       : _task(NULL),
 188         _monitor(new Monitor(Monitor::leaf, "WorkGang dispatcher lock", false, Monitor::_safepoint_check_never)),
 189         _started(0),
 190         _finished(0),
 191         _num_workers(0) {}
 192 
 193   ~MutexGangTaskDispatcher() {
 194     delete _monitor;


 224     _started++;
 225 
 226     // Subtract one to get a zero-indexed worker id.
 227     uint worker_id = _started - 1;
 228 
 229     return WorkData(_task, worker_id);
 230   }
 231 
 232   void worker_done_with_task() {
 233     MonitorLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
 234 
 235     _finished++;
 236 
 237     if (_finished == _num_workers) {
 238       // This will wake up all workers and not only the coordinator.
 239       _monitor->notify_all();
 240     }
 241   }
 242 };
 243 
 244 static GangTaskDispatcher* create_dispatcher(uint workers) {
 245 #if IMPLEMENTS_SEMAPHORE_CLASS
 246   if (UseSemaphoreGCThreadsSynchronization) {
 247     return new SemaphoreGangTaskDispatcher(workers);
 248   }
 249 #endif
 250 
 251   return new MutexGangTaskDispatcher();
 252 }
 253 
 254 WorkGang::WorkGang(const char* name,
 255                    uint  workers,
 256                    bool  are_GC_task_threads,
 257                    bool  are_ConcurrentGC_threads) :
 258     AbstractWorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
 259     _dispatcher(create_dispatcher(workers))
 260 { }
 261 
 262 AbstractGangWorker* WorkGang::allocate_worker(uint worker_id) {
 263   return new GangWorker(this, worker_id);
 264 }
 265 
 266 void WorkGang::run_task(AbstractGangTask* task) {
 267   _dispatcher->coordinator_execute_on_workers(task, active_workers());
 268 }
 269 
 270 AbstractGangWorker::AbstractGangWorker(AbstractWorkGang* gang, uint id) {
 271   _gang = gang;
 272   set_id(id);
 273   set_name("%s#%d", gang->name(), id);
 274 }
 275 
 276 void AbstractGangWorker::run() {
 277   initialize();
 278   loop();
 279 }




  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 #include "precompiled.hpp"
  26 #include "gc/shared/workgroup.hpp"
  27 #include "memory/allocation.hpp"
  28 #include "memory/allocation.inline.hpp"
  29 #include "runtime/atomic.inline.hpp"
  30 #include "runtime/os.hpp"
  31 #include "runtime/semaphore.hpp"
  32 #include "runtime/thread.inline.hpp"

  33 
  34 // Definitions of WorkGang methods.
  35 
  36 // The current implementation will exit if the allocation
  37 // of any worker fails.  Still, return a boolean so that
  38 // a future implementation can possibly do a partial
  39 // initialization of the workers and report such to the
  40 // caller.
  41 bool AbstractWorkGang::initialize_workers() {
  42 
  43   if (TraceWorkGang) {
  44     tty->print_cr("Constructing work gang %s with %d threads",
  45                   name(),
  46                   total_workers());
  47   }
  48   _workers = NEW_C_HEAP_ARRAY(AbstractGangWorker*, total_workers(), mtInternal);
  49   if (_workers == NULL) {
  50     vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
  51     return false;
  52   }


  81   assert(result != NULL, "Indexing to null worker");
  82   return result;
  83 }
  84 
  85 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
  86   uint workers = total_workers();
  87   for (uint i = 0; i < workers; i++) {
  88     worker(i)->print_on(st);
  89     st->cr();
  90   }
  91 }
  92 
  93 void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
  94   assert(tc != NULL, "Null ThreadClosure");
  95   uint workers = total_workers();
  96   for (uint i = 0; i < workers; i++) {
  97     tc->do_thread(worker(i));
  98   }
  99 }
 100 


 101 // WorkGang dispatcher implemented with semaphores.
 102 //
 103 // Semaphores don't require the worker threads to re-claim the lock when they wake up.
 104 // This helps lowering the latency when starting and stopping the worker threads.
 105 class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
 106   // The task currently being dispatched to the GangWorkers.
 107   AbstractGangTask* _task;
 108 
 109   volatile uint _started;
 110   volatile uint _not_finished;
 111 
 112   // Semaphore used to start the GangWorkers.
 113   Semaphore* _start_semaphore;
 114   // Semaphore used to notify the coordinator that all workers are done.
 115   Semaphore* _end_semaphore;
 116 
 117 public:
 118   SemaphoreGangTaskDispatcher() :
 119       _task(NULL),
 120       _started(0),
 121       _not_finished(0),
 122       // Limit the semaphore value to the number of workers.
 123       _start_semaphore(new Semaphore()),
 124       _end_semaphore(new Semaphore())
 125 { }
 126 
 127   ~SemaphoreGangTaskDispatcher() {
 128     delete _start_semaphore;
 129     delete _end_semaphore;
 130   }
 131 
 132   void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
 133     // No workers are allowed to read the state variables until they have been signaled.
 134     _task         = task;
 135     _not_finished = num_workers;
 136 
 137     // Dispatch 'num_workers' number of tasks.
 138     _start_semaphore->signal(num_workers);
 139 
 140     // Wait for the last worker to signal the coordinator.
 141     _end_semaphore->wait();
 142 
 143     // No workers are allowed to read the state variables after the coordinator has been signaled.
 144     _task         = NULL;


 152 
 153     uint num_started = (uint) Atomic::add(1, (volatile jint*)&_started);
 154 
 155     // Subtract one to get a zero-indexed worker id.
 156     uint worker_id = num_started - 1;
 157 
 158     return WorkData(_task, worker_id);
 159   }
 160 
 161   void worker_done_with_task() {
 162     // Mark that the worker is done with the task.
 163     // The worker is not allowed to read the state variables after this line.
 164     uint not_finished = (uint) Atomic::add(-1, (volatile jint*)&_not_finished);
 165 
 166     // The last worker signals to the coordinator that all work is completed.
 167     if (not_finished == 0) {
 168       _end_semaphore->signal();
 169     }
 170   }
 171 };

 172 
 173 class MutexGangTaskDispatcher : public GangTaskDispatcher {
 174   AbstractGangTask* _task;
 175 
 176   volatile uint _started;
 177   volatile uint _finished;
 178   volatile uint _num_workers;
 179 
 180   Monitor* _monitor;
 181 
 182  public:
 183   MutexGangTaskDispatcher()
 184       : _task(NULL),
 185         _monitor(new Monitor(Monitor::leaf, "WorkGang dispatcher lock", false, Monitor::_safepoint_check_never)),
 186         _started(0),
 187         _finished(0),
 188         _num_workers(0) {}
 189 
 190   ~MutexGangTaskDispatcher() {
 191     delete _monitor;


 221     _started++;
 222 
 223     // Subtract one to get a zero-indexed worker id.
 224     uint worker_id = _started - 1;
 225 
 226     return WorkData(_task, worker_id);
 227   }
 228 
 229   void worker_done_with_task() {
 230     MonitorLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag);
 231 
 232     _finished++;
 233 
 234     if (_finished == _num_workers) {
 235       // This will wake up all workers and not only the coordinator.
 236       _monitor->notify_all();
 237     }
 238   }
 239 };
 240 
 241 static GangTaskDispatcher* create_dispatcher() {

 242   if (UseSemaphoreGCThreadsSynchronization) {
 243     return new SemaphoreGangTaskDispatcher();
 244   }

 245 
 246   return new MutexGangTaskDispatcher();
 247 }
 248 
 249 WorkGang::WorkGang(const char* name,
 250                    uint  workers,
 251                    bool  are_GC_task_threads,
 252                    bool  are_ConcurrentGC_threads) :
 253     AbstractWorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
 254     _dispatcher(create_dispatcher())
 255 { }
 256 
 257 AbstractGangWorker* WorkGang::allocate_worker(uint worker_id) {
 258   return new GangWorker(this, worker_id);
 259 }
 260 
 261 void WorkGang::run_task(AbstractGangTask* task) {
 262   _dispatcher->coordinator_execute_on_workers(task, active_workers());
 263 }
 264 
 265 AbstractGangWorker::AbstractGangWorker(AbstractWorkGang* gang, uint id) {
 266   _gang = gang;
 267   set_id(id);
 268   set_name("%s#%d", gang->name(), id);
 269 }
 270 
 271 void AbstractGangWorker::run() {
 272   initialize();
 273   loop();
 274 }


< prev index next >