src/share/vm/gc_implementation/g1/concurrentMark.cpp
Print this page
rev 3708 : 8000244: G1: Ergonomically set MarkStackSize and use virtual space for global marking stack
Summary: Set the value of MarkStackSize to a value based on the number of parallel marking threads with a reasonable minimum. Expand the marking stack if we have to restart marking due to an overflow up to a reasonable maximum. Allocate the underlying space for the marking stack from virtual memory.
Reviewed-by: jmasa
rev 3709 : imported patch reuse-old-marking-stack
@@ -44,31 +44,15 @@
#include "runtime/java.hpp"
#include "services/memTracker.hpp"
// Concurrent marking bit map wrapper
-CMBitMapRO::CMBitMapRO(ReservedSpace rs, int shifter) :
- _bm((uintptr_t*)NULL,0),
+CMBitMapRO::CMBitMapRO(int shifter) :
+ _bm(),
_shifter(shifter) {
- _bmStartWord = (HeapWord*)(rs.base());
- _bmWordSize = rs.size()/HeapWordSize; // rs.size() is in bytes
- ReservedSpace brs(ReservedSpace::allocation_align_size_up(
- (_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
-
- MemTracker::record_virtual_memory_type((address)brs.base(), mtGC);
-
- guarantee(brs.is_reserved(), "couldn't allocate concurrent marking bit map");
- // For now we'll just commit all of the bit map up fromt.
- // Later on we'll try to be more parsimonious with swap.
- guarantee(_virtual_space.initialize(brs, brs.size()),
- "couldn't reseve backing store for concurrent marking bit map");
- assert(_virtual_space.committed_size() == brs.size(),
- "didn't reserve backing store for all of concurrent marking bit map?");
- _bm.set_map((uintptr_t*)_virtual_space.low());
- assert(_virtual_space.committed_size() << (_shifter + LogBitsPerByte) >=
- _bmWordSize, "inconsistency in bit map sizing");
- _bm.set_size(_bmWordSize >> _shifter);
+ _bmStartWord = 0;
+ _bmWordSize = 0;
}
HeapWord* CMBitMapRO::getNextMarkedWordAddress(HeapWord* addr,
HeapWord* limit) const {
// First we must round addr *up* to a possible object boundary.
@@ -106,19 +90,44 @@
assert((diff & ((1 << _shifter) - 1)) == 0, "argument check");
return (int) (diff >> _shifter);
}
#ifndef PRODUCT
-bool CMBitMapRO::covers(ReservedSpace rs) const {
+bool CMBitMapRO::covers(ReservedSpace heap_rs) const {
// assert(_bm.map() == _virtual_space.low(), "map inconsistency");
assert(((size_t)_bm.size() * ((size_t)1 << _shifter)) == _bmWordSize,
"size inconsistency");
- return _bmStartWord == (HeapWord*)(rs.base()) &&
- _bmWordSize == rs.size()>>LogHeapWordSize;
+ return _bmStartWord == (HeapWord*)(heap_rs.base()) &&
+ _bmWordSize == heap_rs.size()>>LogHeapWordSize;
}
#endif
+bool CMBitMap::allocate(ReservedSpace heap_rs) {
+ _bmStartWord = (HeapWord*)(heap_rs.base());
+ _bmWordSize = heap_rs.size()/HeapWordSize; // heap_rs.size() is in bytes
+ ReservedSpace brs(ReservedSpace::allocation_align_size_up(
+ (_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
+ if (!brs.is_reserved()) {
+ warning("ConcurrentMark marking bit map allocation failure");
+ return false;
+ }
+ MemTracker::record_virtual_memory_type((address)brs.base(), mtGC);
+ // For now we'll just commit all of the bit map up front.
+ // Later on we'll try to be more parsimonious with swap.
+ if (!_virtual_space.initialize(brs, brs.size())) {
+ warning("ConcurrentMark marking bit map backing store failure");
+ return false;
+ }
+ assert(_virtual_space.committed_size() == brs.size(),
+ "didn't reserve backing store for all of concurrent marking bit map?");
+ _bm.set_map((uintptr_t*)_virtual_space.low());
+ assert(_virtual_space.committed_size() << (_shifter + LogBitsPerByte) >=
+ _bmWordSize, "inconsistency in bit map sizing");
+ _bm.set_size(_bmWordSize >> _shifter);
+ return true;
+}
+
void CMBitMap::clearAll() {
_bm.clear();
return;
}
@@ -161,24 +170,116 @@
, _drain_in_progress(false)
, _drain_in_progress_yields(false)
#endif
{}
-void CMMarkStack::allocate(size_t size) {
- _base = NEW_C_HEAP_ARRAY(oop, size, mtGC);
- if (_base == NULL) {
- vm_exit_during_initialization("Failed to allocate CM region mark stack");
+bool CMMarkStack::allocate(size_t capacity) {
+ // allocate a stack of the requisite depth
+ ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop)));
+ if (!rs.is_reserved()) {
+ warning("ConcurrentMark MarkStack allocation failure");
+ return false;
}
- _index = 0;
- _capacity = (jint) size;
+ MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
+ if (!_virtual_space.initialize(rs, rs.size())) {
+ warning("ConcurrentMark MarkStack backing store failure");
+ // Release the virtual memory reserved for the marking stack
+ rs.release();
+ return false;
+ }
+ assert(_virtual_space.committed_size() == rs.size(),
+ "Didn't reserve backing store for all of ConcurrentMark stack?");
+ _rs = rs;
+ _base = (oop*) _virtual_space.low();
+ setEmpty();
+ _capacity = (jint) capacity;
_saved_index = -1;
NOT_PRODUCT(_max_depth = 0);
+ return true;
+}
+
+void CMMarkStack::expand() {
+ // Called, during remark, if we've overflown the marking stack during marking.
+ assert(isEmpty(), "stack should been emptied while handling overflow");
+ assert(_capacity <= (jint) MarkStackSizeMax, "stack bigger than permitted");
+ // Clear expansion flag
+ _should_expand = false;
+ if (_capacity == (jint) MarkStackSizeMax) {
+ if (PrintGCDetails && Verbose) {
+ gclog_or_tty->print_cr(" (benign) Can't expand marking stack capacity, at max size limit");
+ }
+ return;
+ }
+ // Double capacity if possible
+ jint new_capacity = MIN2(_capacity*2, (jint) MarkStackSizeMax);
+ // Do not give up existing stack until we have managed to
+ // get the double capacity that we desired.
+ ReservedSpace rs(ReservedSpace::allocation_align_size_up(new_capacity *
+ sizeof(oop)));
+ if (!rs.is_reserved()) {
+ if (PrintGCDetails && Verbose) {
+ // Failed to double capacity, continue;
+ gclog_or_tty->print(" (benign) Failed to expand marking stack capacity from "
+ SIZE_FORMAT "K to " SIZE_FORMAT "K",
+ _capacity / K, new_capacity / K);
+ }
+ return;
+ }
+
+ // Clear the backing store fields associated with the space for the
+ // old marking stack. Note this doesn't actuall release the space.
+ _virtual_space.release();
+
+ // Reinitialize virtual space for the expanded stack.
+ if (!_virtual_space.initialize(rs, rs.size())) {
+ // We failed to commit the the space for the expanded marking stack
+ // Release the expanded reserved space...
+ rs.release();
+ // ... and reinitialize with the previous un-expanded space.
+ if (_virtual_space.initialize(_rs, _rs.size())) {
+ if (PrintGCDetails && Verbose) {
+ gclog_or_tty->print(" (benign) Failed to expand marking stack capacity from "
+ SIZE_FORMAT "K to " SIZE_FORMAT "K",
+ _capacity / K, new_capacity / K);
+ }
+ } else {
+ // The previous backing store space should have been already
+ // committed but we failed to initialize the virtual space
+ // for some reason.
+ fatal("Error re-initializing marking stack with old capacity");
+ }
+ } else {
+ // We successfully committed the space for the expanded marking stack.
+ if (PrintGCDetails && Verbose) {
+ gclog_or_tty->print(" Successfully expanded marking stack capacity from "
+ SIZE_FORMAT "K to " SIZE_FORMAT "K",
+ _capacity / K, new_capacity / K);
+ }
+ // Release the previous (unexpanded) space.
+ _rs.release();
+ // Record the new (expanded) space.
+ _rs = rs;
+ // Record the new capacity
+ _capacity = new_capacity;
+ }
+ assert(_virtual_space.committed_size() == _rs.size(),
+ "Didn't reserve backing store for all of ConcurrentMark stack?");
+ _base = (oop*)(_virtual_space.low());
+ _index = 0;
+}
+
+void CMMarkStack::set_should_expand() {
+ // If we're resetting the marking state because of an
+ // marking stack overflow, record that we should, if
+ // possible, expand the stack.
+ _should_expand = _cm->has_overflown();
}
CMMarkStack::~CMMarkStack() {
if (_base != NULL) {
- FREE_C_HEAP_ARRAY(oop, _base, mtGC);
+ _base = NULL;
+ _virtual_space.release();
}
}
void CMMarkStack::par_push(oop ptr) {
while (true) {
@@ -226,11 +327,10 @@
}
// Otherwise, we need to try again.
}
}
-
void CMMarkStack::par_push_arr(oop* ptr_arr, int n) {
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
jint start = _index;
jint next_index = start + n;
if (next_index > _capacity) {
@@ -242,13 +342,13 @@
for (int i = 0; i < n; i++) {
int ind = start + i;
assert(ind < _capacity, "By overflow test above.");
_base[ind] = ptr_arr[i];
}
+ NOT_PRODUCT(_max_depth = MAX2(_max_depth, next_index));
}
-
bool CMMarkStack::par_pop_arr(oop* ptr_arr, int max, int* n) {
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
jint index = _index;
if (index == 0) {
*n = 0;
@@ -402,23 +502,24 @@
uint ConcurrentMark::scale_parallel_threads(uint n_par_threads) {
return MAX2((n_par_threads + 2) / 4, 1U);
}
-ConcurrentMark::ConcurrentMark(ReservedSpace rs, uint max_regions) :
- _markBitMap1(rs, MinObjAlignment - 1),
- _markBitMap2(rs, MinObjAlignment - 1),
+ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) :
+ _g1h(g1h),
+ _markBitMap1(MinObjAlignment - 1),
+ _markBitMap2(MinObjAlignment - 1),
_parallel_marking_threads(0),
_max_parallel_marking_threads(0),
_sleep_factor(0.0),
_marking_task_overhead(1.0),
_cleanup_sleep_factor(0.0),
_cleanup_task_overhead(1.0),
_cleanup_list("Cleanup List"),
- _region_bm((BitMap::idx_t) max_regions, false /* in_resource_area*/),
- _card_bm((rs.size() + CardTableModRefBS::card_size - 1) >>
+ _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/),
+ _card_bm((heap_rs.size() + CardTableModRefBS::card_size - 1) >>
CardTableModRefBS::card_shift,
false /* in_resource_area*/),
_prevMarkBitMap(&_markBitMap1),
_nextMarkBitMap(&_markBitMap2),
@@ -447,11 +548,12 @@
_total_rs_scrub_time(0.0),
_parallel_workers(NULL),
_count_card_bitmaps(NULL),
- _count_marked_bytes(NULL) {
+ _count_marked_bytes(NULL),
+ _completed_initialization(false) {
CMVerboseLevel verbose_level = (CMVerboseLevel) G1MarkingVerboseLevel;
if (verbose_level < no_verbose) {
verbose_level = no_verbose;
}
if (verbose_level > high_verbose) {
@@ -462,65 +564,38 @@
if (verbose_low()) {
gclog_or_tty->print_cr("[global] init, heap start = "PTR_FORMAT", "
"heap end = "PTR_FORMAT, _heap_start, _heap_end);
}
- _markStack.allocate(MarkStackSize);
+ if (!_markBitMap1.allocate(heap_rs)) {
+ warning("Failed to allocate first CM bit map");
+ return;
+ }
+ if (!_markBitMap2.allocate(heap_rs)) {
+ warning("Failed to allocate second CM bit map");
+ return;
+ }
// Create & start a ConcurrentMark thread.
_cmThread = new ConcurrentMarkThread(this);
assert(cmThread() != NULL, "CM Thread should have been created");
assert(cmThread()->cm() != NULL, "CM Thread should refer to this cm");
- _g1h = G1CollectedHeap::heap();
assert(CGC_lock != NULL, "Where's the CGC_lock?");
- assert(_markBitMap1.covers(rs), "_markBitMap1 inconsistency");
- assert(_markBitMap2.covers(rs), "_markBitMap2 inconsistency");
+ assert(_markBitMap1.covers(heap_rs), "_markBitMap1 inconsistency");
+ assert(_markBitMap2.covers(heap_rs), "_markBitMap2 inconsistency");
SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
satb_qs.set_buffer_size(G1SATBBufferSize);
_root_regions.init(_g1h, this);
- _tasks = NEW_C_HEAP_ARRAY(CMTask*, _max_worker_id, mtGC);
- _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
-
- _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_worker_id, mtGC);
- _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_worker_id, mtGC);
-
- BitMap::idx_t card_bm_size = _card_bm.size();
-
- // so that the assertion in MarkingTaskQueue::task_queue doesn't fail
- _active_tasks = _max_worker_id;
- for (uint i = 0; i < _max_worker_id; ++i) {
- CMTaskQueue* task_queue = new CMTaskQueue();
- task_queue->initialize();
- _task_queues->register_queue(i, task_queue);
-
- _count_card_bitmaps[i] = BitMap(card_bm_size, false);
- _count_marked_bytes[i] = NEW_C_HEAP_ARRAY(size_t, (size_t) max_regions, mtGC);
-
- _tasks[i] = new CMTask(i, this,
- _count_marked_bytes[i],
- &_count_card_bitmaps[i],
- task_queue, _task_queues);
-
- _accum_task_vtime[i] = 0.0;
- }
-
- // Calculate the card number for the bottom of the heap. Used
- // in biasing indexes into the accounting card bitmaps.
- _heap_bottom_card_num =
- intptr_t(uintptr_t(_g1h->reserved_region().start()) >>
- CardTableModRefBS::card_shift);
-
- // Clear all the liveness counting data
- clear_all_count_data();
-
if (ConcGCThreads > ParallelGCThreads) {
- vm_exit_during_initialization("Can't have more ConcGCThreads "
- "than ParallelGCThreads.");
+ warning("Can't have more ConcGCThreads (" UINT32_FORMAT ") "
+ "than ParallelGCThreads (" UINT32_FORMAT ").",
+ ConcGCThreads, ParallelGCThreads);
+ return;
}
if (ParallelGCThreads == 0) {
// if we are not running with any parallel GC threads we will not
// spawn any marking threads either
_parallel_marking_threads = 0;
@@ -588,13 +663,90 @@
} else {
_parallel_workers->initialize_workers();
}
}
+ if (FLAG_IS_DEFAULT(MarkStackSize)) {
+ uintx mark_stack_size =
+ MIN2(MarkStackSizeMax,
+ MAX2(MarkStackSize, (uintx) (parallel_marking_threads() * TASKQUEUE_SIZE)));
+ // Verify that the calculated value for MarkStackSize is in range.
+ // It would be nice to use the private utility routine from Arguments.
+ if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) {
+ warning("Invalid value calculated for MarkStackSize (" UINTX_FORMAT "): "
+ "must be between " UINTX_FORMAT " and " UINTX_FORMAT,
+ mark_stack_size, 1, MarkStackSizeMax);
+ return;
+ }
+ FLAG_SET_ERGO(uintx, MarkStackSize, mark_stack_size);
+ } else {
+ // Verify MarkStackSize is in range.
+ if (FLAG_IS_CMDLINE(MarkStackSize)) {
+ if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
+ if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
+ warning("Invalid value specified for MarkStackSize (" UINTX_FORMAT "): "
+ "must be between " UINTX_FORMAT " and " UINTX_FORMAT,
+ MarkStackSize, 1, MarkStackSizeMax);
+ return;
+ }
+ } else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) {
+ if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
+ warning("Invalid value specified for MarkStackSize (" UINTX_FORMAT ")"
+ " or for MarkStackSizeMax (" UINTX_FORMAT ")",
+ MarkStackSize, MarkStackSizeMax);
+ return;
+ }
+ }
+ }
+ }
+
+ if (!_markStack.allocate(MarkStackSize)) {
+ warning("Failed to allocate CM marking stack");
+ return;
+ }
+
+ _tasks = NEW_C_HEAP_ARRAY(CMTask*, _max_worker_id, mtGC);
+ _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
+
+ _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_worker_id, mtGC);
+ _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_worker_id, mtGC);
+
+ BitMap::idx_t card_bm_size = _card_bm.size();
+
+ // so that the assertion in MarkingTaskQueue::task_queue doesn't fail
+ _active_tasks = _max_worker_id;
+
+ size_t max_regions = (size_t) _g1h->max_regions();
+ for (uint i = 0; i < _max_worker_id; ++i) {
+ CMTaskQueue* task_queue = new CMTaskQueue();
+ task_queue->initialize();
+ _task_queues->register_queue(i, task_queue);
+
+ _count_card_bitmaps[i] = BitMap(card_bm_size, false);
+ _count_marked_bytes[i] = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC);
+
+ _tasks[i] = new CMTask(i, this,
+ _count_marked_bytes[i],
+ &_count_card_bitmaps[i],
+ task_queue, _task_queues);
+
+ _accum_task_vtime[i] = 0.0;
+ }
+
+ // Calculate the card number for the bottom of the heap. Used
+ // in biasing indexes into the accounting card bitmaps.
+ _heap_bottom_card_num =
+ intptr_t(uintptr_t(_g1h->reserved_region().start()) >>
+ CardTableModRefBS::card_shift);
+
+ // Clear all the liveness counting data
+ clear_all_count_data();
+
// so that the call below can read a sensible value
- _heap_start = (HeapWord*) rs.base();
+ _heap_start = (HeapWord*) heap_rs.base();
set_non_marking_state();
+ _completed_initialization = true;
}
void ConcurrentMark::update_g1_committed(bool force) {
// If concurrent marking is not in progress, then we do not need to
// update _heap_end.
@@ -1163,10 +1315,15 @@
/* option */ VerifyOption_G1UseNextMarking);
}
assert(!restart_for_overflow(), "sanity");
}
+ // Expand the marking stack, if we have to and if we can.
+ if (_markStack.should_expand()) {
+ _markStack.expand();
+ }
+
// Reset the marking state if marking completed
if (!restart_for_overflow()) {
set_non_marking_state();
}
@@ -2783,11 +2940,11 @@
_markStack.oops_do(&cl);
// Verify entries on the task queues
for (uint i = 0; i < _max_worker_id; i += 1) {
cl.set_phase(VerifyNoCSetOopsQueues, i);
- OopTaskQueue* queue = _task_queues->queue(i);
+ CMTaskQueue* queue = _task_queues->queue(i);
queue->oops_do(&cl);
}
}
SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
@@ -2838,21 +2995,21 @@
}
}
#endif // PRODUCT
void ConcurrentMark::clear_marking_state(bool clear_overflow) {
- _markStack.setEmpty();
- _markStack.clear_overflow();
+ _markStack.set_should_expand();
+ _markStack.setEmpty(); // Also clears the _markStack overflow flag
if (clear_overflow) {
clear_has_overflown();
} else {
assert(has_overflown(), "pre-condition");
}
_finger = _heap_start;
for (uint i = 0; i < _max_worker_id; ++i) {
- OopTaskQueue* queue = _task_queues->queue(i);
+ CMTaskQueue* queue = _task_queues->queue(i);
queue->set_empty();
}
}
// Aggregate the counting data that was constructed concurrently