src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp

changeset 3294
bca17e38de00
parent 2314
f95d63e2154a
child 3328
6d7d0790074d
     1.1 --- a/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp	Tue Nov 22 04:47:10 2011 -0500
     1.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp	Tue Aug 09 10:16:01 2011 -0700
     1.3 @@ -25,6 +25,7 @@
     1.4  #include "precompiled.hpp"
     1.5  #include "gc_implementation/parallelScavenge/gcTaskManager.hpp"
     1.6  #include "gc_implementation/parallelScavenge/gcTaskThread.hpp"
     1.7 +#include "gc_implementation/shared/adaptiveSizePolicy.hpp"
     1.8  #include "memory/allocation.hpp"
     1.9  #include "memory/allocation.inline.hpp"
    1.10  #include "runtime/mutex.hpp"
    1.11 @@ -181,6 +182,7 @@
    1.12    }
    1.13    set_insert_end(task);
    1.14    increment_length();
    1.15 +  verify_length();
    1.16    if (TraceGCTaskQueue) {
    1.17      print("after:");
    1.18    }
    1.19 @@ -192,7 +194,7 @@
    1.20      tty->print_cr("[" INTPTR_FORMAT "]"
    1.21                    " GCTaskQueue::enqueue(list: "
    1.22                    INTPTR_FORMAT ")",
    1.23 -                  this);
    1.24 +                  this, list);
    1.25      print("before:");
    1.26      list->print("list:");
    1.27    }
    1.28 @@ -211,14 +213,15 @@
    1.29      list->remove_end()->set_older(insert_end());
    1.30      insert_end()->set_newer(list->remove_end());
    1.31      set_insert_end(list->insert_end());
    1.32 +    set_length(length() + list_length);
    1.33      // empty the argument list.
    1.34    }
    1.35 -  set_length(length() + list_length);
    1.36    list->initialize();
    1.37    if (TraceGCTaskQueue) {
    1.38      print("after:");
    1.39      list->print("list:");
    1.40    }
    1.41 +  verify_length();
    1.42  }
    1.43  
    1.44  // Dequeue one task.
    1.45 @@ -288,6 +291,7 @@
    1.46    decrement_length();
    1.47    assert(result->newer() == NULL, "shouldn't be on queue");
    1.48    assert(result->older() == NULL, "shouldn't be on queue");
    1.49 +  verify_length();
    1.50    return result;
    1.51  }
    1.52  
    1.53 @@ -311,22 +315,40 @@
    1.54    result->set_newer(NULL);
    1.55    result->set_older(NULL);
    1.56    decrement_length();
    1.57 +  verify_length();
    1.58    return result;
    1.59  }
    1.60  
    1.61  NOT_PRODUCT(
    1.62 +// Count the elements in the queue and verify the length against
    1.63 +// that count.
    1.64 +void GCTaskQueue::verify_length() const {
    1.65 +  uint count = 0;
    1.66 +  for (GCTask* element = insert_end();
    1.67 +       element != NULL;
    1.68 +       element = element->older()) {
    1.69 +
    1.70 +    count++;
    1.71 +  }
    1.72 +  assert(count == length(), "Length does not match queue");
    1.73 +}
    1.74 +
    1.75  void GCTaskQueue::print(const char* message) const {
    1.76    tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:"
    1.77                  "  insert_end: " INTPTR_FORMAT
    1.78                  "  remove_end: " INTPTR_FORMAT
    1.79 +                "  length:       %d"
    1.80                  "  %s",
    1.81 -                this, insert_end(), remove_end(), message);
    1.82 +                this, insert_end(), remove_end(), length(), message);
    1.83 +  uint count = 0;
    1.84    for (GCTask* element = insert_end();
    1.85         element != NULL;
    1.86         element = element->older()) {
    1.87      element->print("    ");
    1.88 +    count++;
    1.89      tty->cr();
    1.90    }
    1.91 +  tty->print("Total tasks: %d", count);
    1.92  }
    1.93  )
    1.94  
    1.95 @@ -351,12 +373,16 @@
    1.96  //
    1.97  GCTaskManager::GCTaskManager(uint workers) :
    1.98    _workers(workers),
    1.99 +  _active_workers(0),
   1.100 +  _idle_workers(0),
   1.101    _ndc(NULL) {
   1.102    initialize();
   1.103  }
   1.104  
   1.105  GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) :
   1.106    _workers(workers),
   1.107 +  _active_workers(0),
   1.108 +  _idle_workers(0),
   1.109    _ndc(ndc) {
   1.110    initialize();
   1.111  }
   1.112 @@ -373,6 +399,7 @@
   1.113    GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap();
   1.114    _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock());
   1.115    _noop_task = NoopGCTask::create_on_c_heap();
   1.116 +  _idle_inactive_task = WaitForBarrierGCTask::create_on_c_heap();
   1.117    _resource_flag = NEW_C_HEAP_ARRAY(bool, workers());
   1.118    {
   1.119      // Set up worker threads.
   1.120 @@ -418,6 +445,8 @@
   1.121    assert(queue()->is_empty(), "still have queued work");
   1.122    NoopGCTask::destroy(_noop_task);
   1.123    _noop_task = NULL;
   1.124 +  WaitForBarrierGCTask::destroy(_idle_inactive_task);
   1.125 +  _idle_inactive_task = NULL;
   1.126    if (_thread != NULL) {
   1.127      for (uint i = 0; i < workers(); i += 1) {
   1.128        GCTaskThread::destroy(thread(i));
   1.129 @@ -442,6 +471,86 @@
   1.130    }
   1.131  }
   1.132  
   1.133 +void GCTaskManager::set_active_gang() {
   1.134 +  _active_workers =
   1.135 +    AdaptiveSizePolicy::calc_active_workers(workers(),
   1.136 +                                 active_workers(),
   1.137 +                                 Threads::number_of_non_daemon_threads());
   1.138 +
   1.139 +  assert(!all_workers_active() || active_workers() == ParallelGCThreads,
   1.140 +         err_msg("all_workers_active() is  incorrect: "
   1.141 +                 "active %d  ParallelGCThreads %d", active_workers(),
   1.142 +                 ParallelGCThreads));
   1.143 +  if (TraceDynamicGCThreads) {
   1.144 +    gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): "
   1.145 +                           "all_workers_active()  %d  workers %d  "
   1.146 +                           "active  %d  ParallelGCThreads %d ",
   1.147 +                           all_workers_active(), workers(),  active_workers(),
   1.148 +                           ParallelGCThreads);
   1.149 +  }
   1.150 +}
   1.151 +
   1.152 +// Create IdleGCTasks for inactive workers.
   1.153 +// Creates tasks in a ResourceArea and assumes
   1.154 +// an appropriate ResourceMark.
   1.155 +void GCTaskManager::task_idle_workers() {
   1.156 +  {
   1.157 +    int more_inactive_workers = 0;
   1.158 +    {
   1.159 +      // Stop any idle tasks from exiting their IdleGCTask's
   1.160 +      // and get the count for additional IdleGCTask's under
   1.161 +      // the GCTaskManager's monitor so that the "more_inactive_workers"
   1.162 +      // count is correct.
   1.163 +      MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.164 +      _idle_inactive_task->set_should_wait(true);
   1.165 +      // active_workers are a number being requested.  idle_workers
   1.166 +      // are the number currently idle.  If all the workers are being
   1.167 +      // requested to be active but some are already idle, reduce
   1.168 +      // the number of active_workers to be consistent with the
   1.169 +      // number of idle_workers.  The idle_workers are stuck in
   1.170 +      // idle tasks and will no longer be release (since a new GC
   1.171 +      // is starting).  Try later to release enough idle_workers
   1.172 +      // to allow the desired number of active_workers.
   1.173 +      more_inactive_workers =
   1.174 +        workers() - active_workers() - idle_workers();
   1.175 +      if (more_inactive_workers < 0) {
   1.176 +        int reduced_active_workers = active_workers() + more_inactive_workers;
   1.177 +        set_active_workers(reduced_active_workers);
   1.178 +        more_inactive_workers = 0;
   1.179 +      }
   1.180 +      if (TraceDynamicGCThreads) {
   1.181 +        gclog_or_tty->print_cr("JT: %d  workers %d  active  %d  "
   1.182 +                                "idle %d  more %d",
   1.183 +                                Threads::number_of_non_daemon_threads(),
   1.184 +                                workers(),
   1.185 +                                active_workers(),
   1.186 +                                idle_workers(),
   1.187 +                                more_inactive_workers);
   1.188 +      }
   1.189 +    }
   1.190 +    GCTaskQueue* q = GCTaskQueue::create();
   1.191 +    for(uint i = 0; i < (uint) more_inactive_workers; i++) {
   1.192 +      q->enqueue(IdleGCTask::create_on_c_heap());
   1.193 +      increment_idle_workers();
   1.194 +    }
   1.195 +    assert(workers() == active_workers() + idle_workers(),
   1.196 +      "total workers should equal active + inactive");
   1.197 +    add_list(q);
   1.198 +    // GCTaskQueue* q was created in a ResourceArea so a
   1.199 +    // destroy() call is not needed.
   1.200 +  }
   1.201 +}
   1.202 +
   1.203 +void  GCTaskManager::release_idle_workers() {
   1.204 +  {
   1.205 +    MutexLockerEx ml(monitor(),
   1.206 +      Mutex::_no_safepoint_check_flag);
   1.207 +    _idle_inactive_task->set_should_wait(false);
   1.208 +    monitor()->notify_all();
   1.209 +  // Release monitor
   1.210 +  }
   1.211 +}
   1.212 +
   1.213  void GCTaskManager::print_task_time_stamps() {
   1.214    for(uint i=0; i<ParallelGCThreads; i++) {
   1.215      GCTaskThread* t = thread(i);
   1.216 @@ -510,6 +619,13 @@
   1.217    // Release monitor().
   1.218  }
   1.219  
   1.220 +// GC workers wait in get_task() for new work to be added
   1.221 +// to the GCTaskManager's queue.  When new work is added,
   1.222 +// a notify is sent to the waiting GC workers which then
   1.223 +// compete to get tasks.  If a GC worker wakes up and there
   1.224 +// is no work on the queue, it is given a noop_task to execute
   1.225 +// and then loops to find more work.
   1.226 +
   1.227  GCTask* GCTaskManager::get_task(uint which) {
   1.228    GCTask* result = NULL;
   1.229    // Grab the queue lock.
   1.230 @@ -558,8 +674,10 @@
   1.231                    which, result, GCTask::Kind::to_string(result->kind()));
   1.232      tty->print_cr("     %s", result->name());
   1.233    }
   1.234 -  increment_busy_workers();
   1.235 -  increment_delivered_tasks();
   1.236 +  if (!result->is_idle_task()) {
   1.237 +    increment_busy_workers();
   1.238 +    increment_delivered_tasks();
   1.239 +  }
   1.240    return result;
   1.241    // Release monitor().
   1.242  }
   1.243 @@ -622,6 +740,7 @@
   1.244  
   1.245  uint GCTaskManager::decrement_busy_workers() {
   1.246    assert(queue()->own_lock(), "don't own the lock");
   1.247 +  assert(_busy_workers > 0, "About to make a mistake");
   1.248    _busy_workers -= 1;
   1.249    return _busy_workers;
   1.250  }
   1.251 @@ -643,11 +762,28 @@
   1.252    set_resource_flag(which, false);
   1.253  }
   1.254  
   1.255 +// "list" contains tasks that are ready to execute.  Those
   1.256 +// tasks are added to the GCTaskManager's queue of tasks and
   1.257 +// then the GC workers are notified that there is new work to
   1.258 +// do.
   1.259 +//
   1.260 +// Typically different types of tasks can be added to the "list".
   1.261 +// For example in PSScavenge OldToYoungRootsTask, SerialOldToYoungRootsTask,
   1.262 +// ScavengeRootsTask, and StealTask tasks are all added to the list
   1.263 +// and then the GC workers are notified of new work.  The tasks are
   1.264 +// handed out in the order in which they are added to the list
   1.265 +// (although execution is not necessarily in that order).  As long
   1.266 +// as any tasks are running the GCTaskManager will wait for execution
   1.267 +// to complete.  GC workers that execute a stealing task remain in
   1.268 +// the stealing task until all stealing tasks have completed.  The load
   1.269 +// balancing afforded by the stealing tasks work best if the stealing
   1.270 +// tasks are added last to the list.
   1.271 +
   1.272  void GCTaskManager::execute_and_wait(GCTaskQueue* list) {
   1.273    WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create();
   1.274    list->enqueue(fin);
   1.275    add_list(list);
   1.276 -  fin->wait_for();
   1.277 +  fin->wait_for(true /* reset */);
   1.278    // We have to release the barrier tasks!
   1.279    WaitForBarrierGCTask::destroy(fin);
   1.280  }
   1.281 @@ -692,6 +828,72 @@
   1.282  }
   1.283  
   1.284  //
   1.285 +// IdleGCTask
   1.286 +//
   1.287 +
   1.288 +IdleGCTask* IdleGCTask::create() {
   1.289 +  IdleGCTask* result = new IdleGCTask(false);
   1.290 +  return result;
   1.291 +}
   1.292 +
   1.293 +IdleGCTask* IdleGCTask::create_on_c_heap() {
   1.294 +  IdleGCTask* result = new(ResourceObj::C_HEAP) IdleGCTask(true);
   1.295 +  return result;
   1.296 +}
   1.297 +
   1.298 +void IdleGCTask::do_it(GCTaskManager* manager, uint which) {
   1.299 +  WaitForBarrierGCTask* wait_for_task = manager->idle_inactive_task();
   1.300 +  if (TraceGCTaskManager) {
   1.301 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.302 +                  " IdleGCTask:::do_it()"
   1.303 +      "  should_wait: %s",
   1.304 +      this, wait_for_task->should_wait() ? "true" : "false");
   1.305 +  }
   1.306 +  MutexLockerEx ml(manager->monitor(), Mutex::_no_safepoint_check_flag);
   1.307 +  if (TraceDynamicGCThreads) {
   1.308 +    gclog_or_tty->print_cr("--- idle %d", which);
   1.309 +  }
   1.310 +  // Increment has to be done when the idle tasks are created.
   1.311 +  // manager->increment_idle_workers();
   1.312 +  manager->monitor()->notify_all();
   1.313 +  while (wait_for_task->should_wait()) {
   1.314 +    if (TraceGCTaskManager) {
   1.315 +      tty->print_cr("[" INTPTR_FORMAT "]"
   1.316 +                    " IdleGCTask::do_it()"
   1.317 +        "  [" INTPTR_FORMAT "] (%s)->wait()",
   1.318 +        this, manager->monitor(), manager->monitor()->name());
   1.319 +    }
   1.320 +    manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
   1.321 +  }
   1.322 +  manager->decrement_idle_workers();
   1.323 +  if (TraceDynamicGCThreads) {
   1.324 +    gclog_or_tty->print_cr("--- release %d", which);
   1.325 +  }
   1.326 +  if (TraceGCTaskManager) {
   1.327 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.328 +                  " IdleGCTask::do_it() returns"
   1.329 +      "  should_wait: %s",
   1.330 +      this, wait_for_task->should_wait() ? "true" : "false");
   1.331 +  }
   1.332 +  // Release monitor().
   1.333 +}
   1.334 +
   1.335 +void IdleGCTask::destroy(IdleGCTask* that) {
   1.336 +  if (that != NULL) {
   1.337 +    that->destruct();
   1.338 +    if (that->is_c_heap_obj()) {
   1.339 +      FreeHeap(that);
   1.340 +    }
   1.341 +  }
   1.342 +}
   1.343 +
   1.344 +void IdleGCTask::destruct() {
   1.345 +  // This has to know it's superclass structure, just like the constructor.
   1.346 +  this->GCTask::destruct();
   1.347 +  // Nothing else to do.
   1.348 +}
   1.349 +
   1.350 +//
   1.351  // BarrierGCTask
   1.352  //
   1.353  
   1.354 @@ -768,7 +970,8 @@
   1.355  }
   1.356  
   1.357  WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() {
   1.358 -  WaitForBarrierGCTask* result = new WaitForBarrierGCTask(true);
   1.359 +  WaitForBarrierGCTask* result =
   1.360 +    new (ResourceObj::C_HEAP) WaitForBarrierGCTask(true);
   1.361    return result;
   1.362  }
   1.363  
   1.364 @@ -849,7 +1052,7 @@
   1.365    }
   1.366  }
   1.367  
   1.368 -void WaitForBarrierGCTask::wait_for() {
   1.369 +void WaitForBarrierGCTask::wait_for(bool reset) {
   1.370    if (TraceGCTaskManager) {
   1.371      tty->print_cr("[" INTPTR_FORMAT "]"
   1.372                    " WaitForBarrierGCTask::wait_for()"
   1.373 @@ -869,7 +1072,9 @@
   1.374        monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
   1.375      }
   1.376      // Reset the flag in case someone reuses this task.
   1.377 -    set_should_wait(true);
   1.378 +    if (reset) {
   1.379 +      set_should_wait(true);
   1.380 +    }
   1.381      if (TraceGCTaskManager) {
   1.382        tty->print_cr("[" INTPTR_FORMAT "]"
   1.383                      " WaitForBarrierGCTask::wait_for() returns"

mercurial