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"