Mercurial > hg > graal-jvmci-8
annotate src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp @ 3377:2aa9ddbb9e60
7041789: 30% perf regression with c2/arm following 7017732
Summary: Implement a more accurate is_scavengable()
Reviewed-by: stefank, jcoomes, ysr
author | jmasa |
---|---|
date | Tue, 03 May 2011 10:30:34 -0700 |
parents | f95d63e2154a |
children | bca17e38de00 |
rev | line source |
---|---|
0 | 1 /* |
1972 | 2 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" | |
27 #include "gc_implementation/parallelScavenge/gcTaskThread.hpp" | |
28 #include "memory/allocation.hpp" | |
29 #include "memory/allocation.inline.hpp" | |
30 #include "runtime/mutex.hpp" | |
31 #include "runtime/mutexLocker.hpp" | |
0 | 32 |
33 // | |
34 // GCTask | |
35 // | |
36 | |
37 const char* GCTask::Kind::to_string(kind value) { | |
38 const char* result = "unknown GCTask kind"; | |
39 switch (value) { | |
40 default: | |
41 result = "unknown GCTask kind"; | |
42 break; | |
43 case unknown_task: | |
44 result = "unknown task"; | |
45 break; | |
46 case ordinary_task: | |
47 result = "ordinary task"; | |
48 break; | |
49 case barrier_task: | |
50 result = "barrier task"; | |
51 break; | |
52 case noop_task: | |
53 result = "noop task"; | |
54 break; | |
55 } | |
56 return result; | |
57 }; | |
58 | |
59 GCTask::GCTask() : | |
60 _kind(Kind::ordinary_task), | |
61 _affinity(GCTaskManager::sentinel_worker()){ | |
62 initialize(); | |
63 } | |
64 | |
65 GCTask::GCTask(Kind::kind kind) : | |
66 _kind(kind), | |
67 _affinity(GCTaskManager::sentinel_worker()) { | |
68 initialize(); | |
69 } | |
70 | |
71 GCTask::GCTask(uint affinity) : | |
72 _kind(Kind::ordinary_task), | |
73 _affinity(affinity) { | |
74 initialize(); | |
75 } | |
76 | |
77 GCTask::GCTask(Kind::kind kind, uint affinity) : | |
78 _kind(kind), | |
79 _affinity(affinity) { | |
80 initialize(); | |
81 } | |
82 | |
83 void GCTask::initialize() { | |
84 _older = NULL; | |
85 _newer = NULL; | |
86 } | |
87 | |
88 void GCTask::destruct() { | |
89 assert(older() == NULL, "shouldn't have an older task"); | |
90 assert(newer() == NULL, "shouldn't have a newer task"); | |
91 // Nothing to do. | |
92 } | |
93 | |
94 NOT_PRODUCT( | |
95 void GCTask::print(const char* message) const { | |
96 tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT, | |
97 newer(), this, affinity(), older()); | |
98 } | |
99 ) | |
100 | |
101 // | |
102 // GCTaskQueue | |
103 // | |
104 | |
105 GCTaskQueue* GCTaskQueue::create() { | |
106 GCTaskQueue* result = new GCTaskQueue(false); | |
107 if (TraceGCTaskQueue) { | |
108 tty->print_cr("GCTaskQueue::create()" | |
109 " returns " INTPTR_FORMAT, result); | |
110 } | |
111 return result; | |
112 } | |
113 | |
114 GCTaskQueue* GCTaskQueue::create_on_c_heap() { | |
115 GCTaskQueue* result = new(ResourceObj::C_HEAP) GCTaskQueue(true); | |
116 if (TraceGCTaskQueue) { | |
117 tty->print_cr("GCTaskQueue::create_on_c_heap()" | |
118 " returns " INTPTR_FORMAT, | |
119 result); | |
120 } | |
121 return result; | |
122 } | |
123 | |
124 GCTaskQueue::GCTaskQueue(bool on_c_heap) : | |
125 _is_c_heap_obj(on_c_heap) { | |
126 initialize(); | |
127 if (TraceGCTaskQueue) { | |
128 tty->print_cr("[" INTPTR_FORMAT "]" | |
129 " GCTaskQueue::GCTaskQueue() constructor", | |
130 this); | |
131 } | |
132 } | |
133 | |
134 void GCTaskQueue::destruct() { | |
135 // Nothing to do. | |
136 } | |
137 | |
138 void GCTaskQueue::destroy(GCTaskQueue* that) { | |
139 if (TraceGCTaskQueue) { | |
140 tty->print_cr("[" INTPTR_FORMAT "]" | |
141 " GCTaskQueue::destroy()" | |
142 " is_c_heap_obj: %s", | |
143 that, | |
144 that->is_c_heap_obj() ? "true" : "false"); | |
145 } | |
146 // That instance may have been allocated as a CHeapObj, | |
147 // in which case we have to free it explicitly. | |
148 if (that != NULL) { | |
149 that->destruct(); | |
150 assert(that->is_empty(), "should be empty"); | |
151 if (that->is_c_heap_obj()) { | |
152 FreeHeap(that); | |
153 } | |
154 } | |
155 } | |
156 | |
157 void GCTaskQueue::initialize() { | |
158 set_insert_end(NULL); | |
159 set_remove_end(NULL); | |
160 set_length(0); | |
161 } | |
162 | |
163 // Enqueue one task. | |
164 void GCTaskQueue::enqueue(GCTask* task) { | |
165 if (TraceGCTaskQueue) { | |
166 tty->print_cr("[" INTPTR_FORMAT "]" | |
167 " GCTaskQueue::enqueue(task: " | |
168 INTPTR_FORMAT ")", | |
169 this, task); | |
170 print("before:"); | |
171 } | |
172 assert(task != NULL, "shouldn't have null task"); | |
173 assert(task->older() == NULL, "shouldn't be on queue"); | |
174 assert(task->newer() == NULL, "shouldn't be on queue"); | |
175 task->set_newer(NULL); | |
176 task->set_older(insert_end()); | |
177 if (is_empty()) { | |
178 set_remove_end(task); | |
179 } else { | |
180 insert_end()->set_newer(task); | |
181 } | |
182 set_insert_end(task); | |
183 increment_length(); | |
184 if (TraceGCTaskQueue) { | |
185 print("after:"); | |
186 } | |
187 } | |
188 | |
189 // Enqueue a whole list of tasks. Empties the argument list. | |
190 void GCTaskQueue::enqueue(GCTaskQueue* list) { | |
191 if (TraceGCTaskQueue) { | |
192 tty->print_cr("[" INTPTR_FORMAT "]" | |
193 " GCTaskQueue::enqueue(list: " | |
194 INTPTR_FORMAT ")", | |
195 this); | |
196 print("before:"); | |
197 list->print("list:"); | |
198 } | |
199 if (list->is_empty()) { | |
200 // Enqueuing the empty list: nothing to do. | |
201 return; | |
202 } | |
203 uint list_length = list->length(); | |
204 if (is_empty()) { | |
205 // Enqueuing to empty list: just acquire elements. | |
206 set_insert_end(list->insert_end()); | |
207 set_remove_end(list->remove_end()); | |
208 set_length(list_length); | |
209 } else { | |
210 // Prepend argument list to our queue. | |
211 list->remove_end()->set_older(insert_end()); | |
212 insert_end()->set_newer(list->remove_end()); | |
213 set_insert_end(list->insert_end()); | |
214 // empty the argument list. | |
215 } | |
216 set_length(length() + list_length); | |
217 list->initialize(); | |
218 if (TraceGCTaskQueue) { | |
219 print("after:"); | |
220 list->print("list:"); | |
221 } | |
222 } | |
223 | |
224 // Dequeue one task. | |
225 GCTask* GCTaskQueue::dequeue() { | |
226 if (TraceGCTaskQueue) { | |
227 tty->print_cr("[" INTPTR_FORMAT "]" | |
228 " GCTaskQueue::dequeue()", this); | |
229 print("before:"); | |
230 } | |
231 assert(!is_empty(), "shouldn't dequeue from empty list"); | |
232 GCTask* result = remove(); | |
233 assert(result != NULL, "shouldn't have NULL task"); | |
234 if (TraceGCTaskQueue) { | |
235 tty->print_cr(" return: " INTPTR_FORMAT, result); | |
236 print("after:"); | |
237 } | |
238 return result; | |
239 } | |
240 | |
241 // Dequeue one task, preferring one with affinity. | |
242 GCTask* GCTaskQueue::dequeue(uint affinity) { | |
243 if (TraceGCTaskQueue) { | |
244 tty->print_cr("[" INTPTR_FORMAT "]" | |
245 " GCTaskQueue::dequeue(%u)", this, affinity); | |
246 print("before:"); | |
247 } | |
248 assert(!is_empty(), "shouldn't dequeue from empty list"); | |
249 // Look down to the next barrier for a task with this affinity. | |
250 GCTask* result = NULL; | |
251 for (GCTask* element = remove_end(); | |
252 element != NULL; | |
253 element = element->newer()) { | |
254 if (element->is_barrier_task()) { | |
255 // Don't consider barrier tasks, nor past them. | |
256 result = NULL; | |
257 break; | |
258 } | |
259 if (element->affinity() == affinity) { | |
260 result = remove(element); | |
261 break; | |
262 } | |
263 } | |
264 // If we didn't find anything with affinity, just take the next task. | |
265 if (result == NULL) { | |
266 result = remove(); | |
267 } | |
268 if (TraceGCTaskQueue) { | |
269 tty->print_cr(" return: " INTPTR_FORMAT, result); | |
270 print("after:"); | |
271 } | |
272 return result; | |
273 } | |
274 | |
275 GCTask* GCTaskQueue::remove() { | |
276 // Dequeue from remove end. | |
277 GCTask* result = remove_end(); | |
278 assert(result != NULL, "shouldn't have null task"); | |
279 assert(result->older() == NULL, "not the remove_end"); | |
280 set_remove_end(result->newer()); | |
281 if (remove_end() == NULL) { | |
282 assert(insert_end() == result, "not a singleton"); | |
283 set_insert_end(NULL); | |
284 } else { | |
285 remove_end()->set_older(NULL); | |
286 } | |
287 result->set_newer(NULL); | |
288 decrement_length(); | |
289 assert(result->newer() == NULL, "shouldn't be on queue"); | |
290 assert(result->older() == NULL, "shouldn't be on queue"); | |
291 return result; | |
292 } | |
293 | |
294 GCTask* GCTaskQueue::remove(GCTask* task) { | |
295 // This is slightly more work, and has slightly fewer asserts | |
296 // than removing from the remove end. | |
297 assert(task != NULL, "shouldn't have null task"); | |
298 GCTask* result = task; | |
299 if (result->newer() != NULL) { | |
300 result->newer()->set_older(result->older()); | |
301 } else { | |
302 assert(insert_end() == result, "not youngest"); | |
303 set_insert_end(result->older()); | |
304 } | |
305 if (result->older() != NULL) { | |
306 result->older()->set_newer(result->newer()); | |
307 } else { | |
308 assert(remove_end() == result, "not oldest"); | |
309 set_remove_end(result->newer()); | |
310 } | |
311 result->set_newer(NULL); | |
312 result->set_older(NULL); | |
313 decrement_length(); | |
314 return result; | |
315 } | |
316 | |
317 NOT_PRODUCT( | |
318 void GCTaskQueue::print(const char* message) const { | |
319 tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:" | |
320 " insert_end: " INTPTR_FORMAT | |
321 " remove_end: " INTPTR_FORMAT | |
322 " %s", | |
323 this, insert_end(), remove_end(), message); | |
324 for (GCTask* element = insert_end(); | |
325 element != NULL; | |
326 element = element->older()) { | |
327 element->print(" "); | |
328 tty->cr(); | |
329 } | |
330 } | |
331 ) | |
332 | |
333 // | |
334 // SynchronizedGCTaskQueue | |
335 // | |
336 | |
337 SynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg, | |
338 Monitor * lock_arg) : | |
339 _unsynchronized_queue(queue_arg), | |
340 _lock(lock_arg) { | |
341 assert(unsynchronized_queue() != NULL, "null queue"); | |
342 assert(lock() != NULL, "null lock"); | |
343 } | |
344 | |
345 SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() { | |
346 // Nothing to do. | |
347 } | |
348 | |
349 // | |
350 // GCTaskManager | |
351 // | |
352 GCTaskManager::GCTaskManager(uint workers) : | |
353 _workers(workers), | |
354 _ndc(NULL) { | |
355 initialize(); | |
356 } | |
357 | |
358 GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) : | |
359 _workers(workers), | |
360 _ndc(ndc) { | |
361 initialize(); | |
362 } | |
363 | |
364 void GCTaskManager::initialize() { | |
365 if (TraceGCTaskManager) { | |
366 tty->print_cr("GCTaskManager::initialize: workers: %u", workers()); | |
367 } | |
368 assert(workers() != 0, "no workers"); | |
369 _monitor = new Monitor(Mutex::barrier, // rank | |
370 "GCTaskManager monitor", // name | |
371 Mutex::_allow_vm_block_flag); // allow_vm_block | |
372 // The queue for the GCTaskManager must be a CHeapObj. | |
373 GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); | |
374 _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); | |
375 _noop_task = NoopGCTask::create_on_c_heap(); | |
376 _resource_flag = NEW_C_HEAP_ARRAY(bool, workers()); | |
377 { | |
378 // Set up worker threads. | |
379 // Distribute the workers among the available processors, | |
380 // unless we were told not to, or if the os doesn't want to. | |
381 uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers()); | |
382 if (!BindGCTaskThreadsToCPUs || | |
383 !os::distribute_processes(workers(), processor_assignment)) { | |
384 for (uint a = 0; a < workers(); a += 1) { | |
385 processor_assignment[a] = sentinel_worker(); | |
386 } | |
387 } | |
388 _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers()); | |
389 for (uint t = 0; t < workers(); t += 1) { | |
390 set_thread(t, GCTaskThread::create(this, t, processor_assignment[t])); | |
391 } | |
392 if (TraceGCTaskThread) { | |
393 tty->print("GCTaskManager::initialize: distribution:"); | |
394 for (uint t = 0; t < workers(); t += 1) { | |
395 tty->print(" %u", processor_assignment[t]); | |
396 } | |
397 tty->cr(); | |
398 } | |
399 FREE_C_HEAP_ARRAY(uint, processor_assignment); | |
400 } | |
401 reset_busy_workers(); | |
402 set_unblocked(); | |
403 for (uint w = 0; w < workers(); w += 1) { | |
404 set_resource_flag(w, false); | |
405 } | |
406 reset_delivered_tasks(); | |
407 reset_completed_tasks(); | |
408 reset_noop_tasks(); | |
409 reset_barriers(); | |
410 reset_emptied_queue(); | |
411 for (uint s = 0; s < workers(); s += 1) { | |
412 thread(s)->start(); | |
413 } | |
414 } | |
415 | |
416 GCTaskManager::~GCTaskManager() { | |
417 assert(busy_workers() == 0, "still have busy workers"); | |
418 assert(queue()->is_empty(), "still have queued work"); | |
419 NoopGCTask::destroy(_noop_task); | |
420 _noop_task = NULL; | |
421 if (_thread != NULL) { | |
422 for (uint i = 0; i < workers(); i += 1) { | |
423 GCTaskThread::destroy(thread(i)); | |
424 set_thread(i, NULL); | |
425 } | |
426 FREE_C_HEAP_ARRAY(GCTaskThread*, _thread); | |
427 _thread = NULL; | |
428 } | |
429 if (_resource_flag != NULL) { | |
430 FREE_C_HEAP_ARRAY(bool, _resource_flag); | |
431 _resource_flag = NULL; | |
432 } | |
433 if (queue() != NULL) { | |
434 GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue(); | |
435 GCTaskQueue::destroy(unsynchronized_queue); | |
436 SynchronizedGCTaskQueue::destroy(queue()); | |
437 _queue = NULL; | |
438 } | |
439 if (monitor() != NULL) { | |
440 delete monitor(); | |
441 _monitor = NULL; | |
442 } | |
443 } | |
444 | |
445 void GCTaskManager::print_task_time_stamps() { | |
446 for(uint i=0; i<ParallelGCThreads; i++) { | |
447 GCTaskThread* t = thread(i); | |
448 t->print_task_time_stamps(); | |
449 } | |
450 } | |
451 | |
452 void GCTaskManager::print_threads_on(outputStream* st) { | |
453 uint num_thr = workers(); | |
454 for (uint i = 0; i < num_thr; i++) { | |
455 thread(i)->print_on(st); | |
456 st->cr(); | |
457 } | |
458 } | |
459 | |
460 void GCTaskManager::threads_do(ThreadClosure* tc) { | |
461 assert(tc != NULL, "Null ThreadClosure"); | |
462 uint num_thr = workers(); | |
463 for (uint i = 0; i < num_thr; i++) { | |
464 tc->do_thread(thread(i)); | |
465 } | |
466 } | |
467 | |
468 GCTaskThread* GCTaskManager::thread(uint which) { | |
469 assert(which < workers(), "index out of bounds"); | |
470 assert(_thread[which] != NULL, "shouldn't have null thread"); | |
471 return _thread[which]; | |
472 } | |
473 | |
474 void GCTaskManager::set_thread(uint which, GCTaskThread* value) { | |
475 assert(which < workers(), "index out of bounds"); | |
476 assert(value != NULL, "shouldn't have null thread"); | |
477 _thread[which] = value; | |
478 } | |
479 | |
480 void GCTaskManager::add_task(GCTask* task) { | |
481 assert(task != NULL, "shouldn't have null task"); | |
482 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
483 if (TraceGCTaskManager) { | |
484 tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])", | |
485 task, GCTask::Kind::to_string(task->kind())); | |
486 } | |
487 queue()->enqueue(task); | |
488 // Notify with the lock held to avoid missed notifies. | |
489 if (TraceGCTaskManager) { | |
490 tty->print_cr(" GCTaskManager::add_task (%s)->notify_all", | |
491 monitor()->name()); | |
492 } | |
493 (void) monitor()->notify_all(); | |
494 // Release monitor(). | |
495 } | |
496 | |
497 void GCTaskManager::add_list(GCTaskQueue* list) { | |
498 assert(list != NULL, "shouldn't have null task"); | |
499 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
500 if (TraceGCTaskManager) { | |
501 tty->print_cr("GCTaskManager::add_list(%u)", list->length()); | |
502 } | |
503 queue()->enqueue(list); | |
504 // Notify with the lock held to avoid missed notifies. | |
505 if (TraceGCTaskManager) { | |
506 tty->print_cr(" GCTaskManager::add_list (%s)->notify_all", | |
507 monitor()->name()); | |
508 } | |
509 (void) monitor()->notify_all(); | |
510 // Release monitor(). | |
511 } | |
512 | |
513 GCTask* GCTaskManager::get_task(uint which) { | |
514 GCTask* result = NULL; | |
515 // Grab the queue lock. | |
516 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
517 // Wait while the queue is block or | |
518 // there is nothing to do, except maybe release resources. | |
519 while (is_blocked() || | |
520 (queue()->is_empty() && !should_release_resources(which))) { | |
521 if (TraceGCTaskManager) { | |
522 tty->print_cr("GCTaskManager::get_task(%u)" | |
523 " blocked: %s" | |
524 " empty: %s" | |
525 " release: %s", | |
526 which, | |
527 is_blocked() ? "true" : "false", | |
528 queue()->is_empty() ? "true" : "false", | |
529 should_release_resources(which) ? "true" : "false"); | |
530 tty->print_cr(" => (%s)->wait()", | |
531 monitor()->name()); | |
532 } | |
533 monitor()->wait(Mutex::_no_safepoint_check_flag, 0); | |
534 } | |
535 // We've reacquired the queue lock here. | |
536 // Figure out which condition caused us to exit the loop above. | |
537 if (!queue()->is_empty()) { | |
538 if (UseGCTaskAffinity) { | |
539 result = queue()->dequeue(which); | |
540 } else { | |
541 result = queue()->dequeue(); | |
542 } | |
543 if (result->is_barrier_task()) { | |
544 assert(which != sentinel_worker(), | |
545 "blocker shouldn't be bogus"); | |
546 set_blocking_worker(which); | |
547 } | |
548 } else { | |
549 // The queue is empty, but we were woken up. | |
550 // Just hand back a Noop task, | |
551 // in case someone wanted us to release resources, or whatever. | |
552 result = noop_task(); | |
553 increment_noop_tasks(); | |
554 } | |
555 assert(result != NULL, "shouldn't have null task"); | |
556 if (TraceGCTaskManager) { | |
557 tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]", | |
558 which, result, GCTask::Kind::to_string(result->kind())); | |
559 tty->print_cr(" %s", result->name()); | |
560 } | |
561 increment_busy_workers(); | |
562 increment_delivered_tasks(); | |
563 return result; | |
564 // Release monitor(). | |
565 } | |
566 | |
567 void GCTaskManager::note_completion(uint which) { | |
568 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
569 if (TraceGCTaskManager) { | |
570 tty->print_cr("GCTaskManager::note_completion(%u)", which); | |
571 } | |
572 // If we are blocked, check if the completing thread is the blocker. | |
573 if (blocking_worker() == which) { | |
574 assert(blocking_worker() != sentinel_worker(), | |
575 "blocker shouldn't be bogus"); | |
576 increment_barriers(); | |
577 set_unblocked(); | |
578 } | |
579 increment_completed_tasks(); | |
580 uint active = decrement_busy_workers(); | |
581 if ((active == 0) && (queue()->is_empty())) { | |
582 increment_emptied_queue(); | |
583 if (TraceGCTaskManager) { | |
584 tty->print_cr(" GCTaskManager::note_completion(%u) done", which); | |
585 } | |
586 // Notify client that we are done. | |
587 NotifyDoneClosure* ndc = notify_done_closure(); | |
588 if (ndc != NULL) { | |
589 ndc->notify(this); | |
590 } | |
591 } | |
592 if (TraceGCTaskManager) { | |
593 tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", | |
594 which, monitor()->name()); | |
595 tty->print_cr(" " | |
596 " blocked: %s" | |
597 " empty: %s" | |
598 " release: %s", | |
599 is_blocked() ? "true" : "false", | |
600 queue()->is_empty() ? "true" : "false", | |
601 should_release_resources(which) ? "true" : "false"); | |
602 tty->print_cr(" " | |
603 " delivered: %u" | |
604 " completed: %u" | |
605 " barriers: %u" | |
606 " emptied: %u", | |
607 delivered_tasks(), | |
608 completed_tasks(), | |
609 barriers(), | |
610 emptied_queue()); | |
611 } | |
612 // Tell everyone that a task has completed. | |
613 (void) monitor()->notify_all(); | |
614 // Release monitor(). | |
615 } | |
616 | |
617 uint GCTaskManager::increment_busy_workers() { | |
618 assert(queue()->own_lock(), "don't own the lock"); | |
619 _busy_workers += 1; | |
620 return _busy_workers; | |
621 } | |
622 | |
623 uint GCTaskManager::decrement_busy_workers() { | |
624 assert(queue()->own_lock(), "don't own the lock"); | |
625 _busy_workers -= 1; | |
626 return _busy_workers; | |
627 } | |
628 | |
629 void GCTaskManager::release_all_resources() { | |
630 // If you want this to be done atomically, do it in a BarrierGCTask. | |
631 for (uint i = 0; i < workers(); i += 1) { | |
632 set_resource_flag(i, true); | |
633 } | |
634 } | |
635 | |
636 bool GCTaskManager::should_release_resources(uint which) { | |
637 // This can be done without a lock because each thread reads one element. | |
638 return resource_flag(which); | |
639 } | |
640 | |
641 void GCTaskManager::note_release(uint which) { | |
642 // This can be done without a lock because each thread writes one element. | |
643 set_resource_flag(which, false); | |
644 } | |
645 | |
646 void GCTaskManager::execute_and_wait(GCTaskQueue* list) { | |
647 WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create(); | |
648 list->enqueue(fin); | |
649 add_list(list); | |
650 fin->wait_for(); | |
651 // We have to release the barrier tasks! | |
652 WaitForBarrierGCTask::destroy(fin); | |
653 } | |
654 | |
655 bool GCTaskManager::resource_flag(uint which) { | |
656 assert(which < workers(), "index out of bounds"); | |
657 return _resource_flag[which]; | |
658 } | |
659 | |
660 void GCTaskManager::set_resource_flag(uint which, bool value) { | |
661 assert(which < workers(), "index out of bounds"); | |
662 _resource_flag[which] = value; | |
663 } | |
664 | |
665 // | |
666 // NoopGCTask | |
667 // | |
668 | |
669 NoopGCTask* NoopGCTask::create() { | |
670 NoopGCTask* result = new NoopGCTask(false); | |
671 return result; | |
672 } | |
673 | |
674 NoopGCTask* NoopGCTask::create_on_c_heap() { | |
675 NoopGCTask* result = new(ResourceObj::C_HEAP) NoopGCTask(true); | |
676 return result; | |
677 } | |
678 | |
679 void NoopGCTask::destroy(NoopGCTask* that) { | |
680 if (that != NULL) { | |
681 that->destruct(); | |
682 if (that->is_c_heap_obj()) { | |
683 FreeHeap(that); | |
684 } | |
685 } | |
686 } | |
687 | |
688 void NoopGCTask::destruct() { | |
689 // This has to know it's superclass structure, just like the constructor. | |
690 this->GCTask::destruct(); | |
691 // Nothing else to do. | |
692 } | |
693 | |
694 // | |
695 // BarrierGCTask | |
696 // | |
697 | |
698 void BarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
699 // Wait for this to be the only busy worker. | |
700 // ??? I thought of having a StackObj class | |
701 // whose constructor would grab the lock and come to the barrier, | |
702 // and whose destructor would release the lock, | |
703 // but that seems like too much mechanism for two lines of code. | |
704 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
705 do_it_internal(manager, which); | |
706 // Release manager->lock(). | |
707 } | |
708 | |
709 void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { | |
710 // Wait for this to be the only busy worker. | |
711 assert(manager->monitor()->owned_by_self(), "don't own the lock"); | |
712 assert(manager->is_blocked(), "manager isn't blocked"); | |
713 while (manager->busy_workers() > 1) { | |
714 if (TraceGCTaskManager) { | |
715 tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers", | |
716 which, manager->busy_workers()); | |
717 } | |
718 manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); | |
719 } | |
720 } | |
721 | |
722 void BarrierGCTask::destruct() { | |
723 this->GCTask::destruct(); | |
724 // Nothing else to do. | |
725 } | |
726 | |
727 // | |
728 // ReleasingBarrierGCTask | |
729 // | |
730 | |
731 void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
732 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
733 do_it_internal(manager, which); | |
734 manager->release_all_resources(); | |
735 // Release manager->lock(). | |
736 } | |
737 | |
738 void ReleasingBarrierGCTask::destruct() { | |
739 this->BarrierGCTask::destruct(); | |
740 // Nothing else to do. | |
741 } | |
742 | |
743 // | |
744 // NotifyingBarrierGCTask | |
745 // | |
746 | |
747 void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
748 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
749 do_it_internal(manager, which); | |
750 NotifyDoneClosure* ndc = notify_done_closure(); | |
751 if (ndc != NULL) { | |
752 ndc->notify(manager); | |
753 } | |
754 // Release manager->lock(). | |
755 } | |
756 | |
757 void NotifyingBarrierGCTask::destruct() { | |
758 this->BarrierGCTask::destruct(); | |
759 // Nothing else to do. | |
760 } | |
761 | |
762 // | |
763 // WaitForBarrierGCTask | |
764 // | |
765 WaitForBarrierGCTask* WaitForBarrierGCTask::create() { | |
766 WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false); | |
767 return result; | |
768 } | |
769 | |
770 WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() { | |
771 WaitForBarrierGCTask* result = new WaitForBarrierGCTask(true); | |
772 return result; | |
773 } | |
774 | |
775 WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) : | |
776 _is_c_heap_obj(on_c_heap) { | |
777 _monitor = MonitorSupply::reserve(); | |
778 set_should_wait(true); | |
779 if (TraceGCTaskManager) { | |
780 tty->print_cr("[" INTPTR_FORMAT "]" | |
781 " WaitForBarrierGCTask::WaitForBarrierGCTask()" | |
782 " monitor: " INTPTR_FORMAT, | |
783 this, monitor()); | |
784 } | |
785 } | |
786 | |
787 void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { | |
788 if (that != NULL) { | |
789 if (TraceGCTaskManager) { | |
790 tty->print_cr("[" INTPTR_FORMAT "]" | |
791 " WaitForBarrierGCTask::destroy()" | |
792 " is_c_heap_obj: %s" | |
793 " monitor: " INTPTR_FORMAT, | |
794 that, | |
795 that->is_c_heap_obj() ? "true" : "false", | |
796 that->monitor()); | |
797 } | |
798 that->destruct(); | |
799 if (that->is_c_heap_obj()) { | |
800 FreeHeap(that); | |
801 } | |
802 } | |
803 } | |
804 | |
805 void WaitForBarrierGCTask::destruct() { | |
806 assert(monitor() != NULL, "monitor should not be NULL"); | |
807 if (TraceGCTaskManager) { | |
808 tty->print_cr("[" INTPTR_FORMAT "]" | |
809 " WaitForBarrierGCTask::destruct()" | |
810 " monitor: " INTPTR_FORMAT, | |
811 this, monitor()); | |
812 } | |
813 this->BarrierGCTask::destruct(); | |
814 // Clean up that should be in the destructor, | |
815 // except that ResourceMarks don't call destructors. | |
816 if (monitor() != NULL) { | |
817 MonitorSupply::release(monitor()); | |
818 } | |
819 _monitor = (Monitor*) 0xDEAD000F; | |
820 } | |
821 | |
822 void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
823 if (TraceGCTaskManager) { | |
824 tty->print_cr("[" INTPTR_FORMAT "]" | |
825 " WaitForBarrierGCTask::do_it() waiting for idle" | |
826 " monitor: " INTPTR_FORMAT, | |
827 this, monitor()); | |
828 } | |
829 { | |
830 // First, wait for the barrier to arrive. | |
831 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
832 do_it_internal(manager, which); | |
833 // Release manager->lock(). | |
834 } | |
835 { | |
836 // Then notify the waiter. | |
837 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
838 set_should_wait(false); | |
839 // Waiter doesn't miss the notify in the wait_for method | |
840 // since it checks the flag after grabbing the monitor. | |
841 if (TraceGCTaskManager) { | |
842 tty->print_cr("[" INTPTR_FORMAT "]" | |
843 " WaitForBarrierGCTask::do_it()" | |
844 " [" INTPTR_FORMAT "] (%s)->notify_all()", | |
845 this, monitor(), monitor()->name()); | |
846 } | |
847 monitor()->notify_all(); | |
848 // Release monitor(). | |
849 } | |
850 } | |
851 | |
852 void WaitForBarrierGCTask::wait_for() { | |
853 if (TraceGCTaskManager) { | |
854 tty->print_cr("[" INTPTR_FORMAT "]" | |
855 " WaitForBarrierGCTask::wait_for()" | |
856 " should_wait: %s", | |
857 this, should_wait() ? "true" : "false"); | |
858 } | |
859 { | |
860 // Grab the lock and check again. | |
861 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
862 while (should_wait()) { | |
863 if (TraceGCTaskManager) { | |
864 tty->print_cr("[" INTPTR_FORMAT "]" | |
865 " WaitForBarrierGCTask::wait_for()" | |
866 " [" INTPTR_FORMAT "] (%s)->wait()", | |
867 this, monitor(), monitor()->name()); | |
868 } | |
869 monitor()->wait(Mutex::_no_safepoint_check_flag, 0); | |
870 } | |
871 // Reset the flag in case someone reuses this task. | |
872 set_should_wait(true); | |
873 if (TraceGCTaskManager) { | |
874 tty->print_cr("[" INTPTR_FORMAT "]" | |
875 " WaitForBarrierGCTask::wait_for() returns" | |
876 " should_wait: %s", | |
877 this, should_wait() ? "true" : "false"); | |
878 } | |
879 // Release monitor(). | |
880 } | |
881 } | |
882 | |
883 Mutex* MonitorSupply::_lock = NULL; | |
884 GrowableArray<Monitor*>* MonitorSupply::_freelist = NULL; | |
885 | |
886 Monitor* MonitorSupply::reserve() { | |
887 Monitor* result = NULL; | |
888 // Lazy initialization: possible race. | |
889 if (lock() == NULL) { | |
890 _lock = new Mutex(Mutex::barrier, // rank | |
891 "MonitorSupply mutex", // name | |
892 Mutex::_allow_vm_block_flag); // allow_vm_block | |
893 } | |
894 { | |
895 MutexLockerEx ml(lock()); | |
896 // Lazy initialization. | |
897 if (freelist() == NULL) { | |
898 _freelist = | |
899 new(ResourceObj::C_HEAP) GrowableArray<Monitor*>(ParallelGCThreads, | |
900 true); | |
901 } | |
902 if (! freelist()->is_empty()) { | |
903 result = freelist()->pop(); | |
904 } else { | |
905 result = new Monitor(Mutex::barrier, // rank | |
906 "MonitorSupply monitor", // name | |
907 Mutex::_allow_vm_block_flag); // allow_vm_block | |
908 } | |
909 guarantee(result != NULL, "shouldn't return NULL"); | |
910 assert(!result->is_locked(), "shouldn't be locked"); | |
911 // release lock(). | |
912 } | |
913 return result; | |
914 } | |
915 | |
916 void MonitorSupply::release(Monitor* instance) { | |
917 assert(instance != NULL, "shouldn't release NULL"); | |
918 assert(!instance->is_locked(), "shouldn't be locked"); | |
919 { | |
920 MutexLockerEx ml(lock()); | |
921 freelist()->push(instance); | |
922 // release lock(). | |
923 } | |
924 } |