8211718: Supporting multiple concurrent OopStorage iterators

Reviewed-by: pliden, kbarrett
This commit is contained in:
Erik Österlund 2018-10-08 14:48:12 +02:00
parent 90d6bbd01a
commit b658954d7e
3 changed files with 18 additions and 25 deletions

View File

@ -727,7 +727,7 @@ OopStorage::OopStorage(const char* name,
_allocation_mutex(allocation_mutex), _allocation_mutex(allocation_mutex),
_active_mutex(active_mutex), _active_mutex(active_mutex),
_allocation_count(0), _allocation_count(0),
_concurrent_iteration_active(false) _concurrent_iteration_count(0)
{ {
_active_array->increment_refcount(); _active_array->increment_refcount();
assert(_active_mutex->rank() < _allocation_mutex->rank(), assert(_active_mutex->rank() < _allocation_mutex->rank(),
@ -769,7 +769,7 @@ void OopStorage::delete_empty_blocks_safepoint() {
// blocks available for deletion. // blocks available for deletion.
while (reduce_deferred_updates()) {} while (reduce_deferred_updates()) {}
// Don't interfere with a concurrent iteration. // Don't interfere with a concurrent iteration.
if (_concurrent_iteration_active) return; if (_concurrent_iteration_count > 0) return;
// Delete empty (and otherwise deletable) blocks from end of _allocation_list. // Delete empty (and otherwise deletable) blocks from end of _allocation_list.
for (Block* block = _allocation_list.tail(); for (Block* block = _allocation_list.tail();
(block != NULL) && block->is_deletable(); (block != NULL) && block->is_deletable();
@ -804,7 +804,7 @@ void OopStorage::delete_empty_blocks_concurrent() {
{ {
MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag); MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag);
// Don't interfere with a concurrent iteration. // Don't interfere with a concurrent iteration.
if (_concurrent_iteration_active) return; if (_concurrent_iteration_count > 0) return;
_active_array->remove(block); _active_array->remove(block);
} }
// Remove block from _allocation_list and delete it. // Remove block from _allocation_list and delete it.
@ -875,7 +875,7 @@ OopStorage::BasicParState::BasicParState(const OopStorage* storage,
_concurrent(concurrent) _concurrent(concurrent)
{ {
assert(estimated_thread_count > 0, "estimated thread count must be positive"); assert(estimated_thread_count > 0, "estimated thread count must be positive");
update_iteration_state(true); update_concurrent_iteration_count(1);
// Get the block count *after* iteration state updated, so concurrent // Get the block count *after* iteration state updated, so concurrent
// empty block deletion is suppressed and can't reduce the count. But // empty block deletion is suppressed and can't reduce the count. But
// ensure the count we use was written after the block with that count // ensure the count we use was written after the block with that count
@ -885,14 +885,14 @@ OopStorage::BasicParState::BasicParState(const OopStorage* storage,
OopStorage::BasicParState::~BasicParState() { OopStorage::BasicParState::~BasicParState() {
_storage->relinquish_block_array(_active_array); _storage->relinquish_block_array(_active_array);
update_iteration_state(false); update_concurrent_iteration_count(-1);
} }
void OopStorage::BasicParState::update_iteration_state(bool value) { void OopStorage::BasicParState::update_concurrent_iteration_count(int value) {
if (_concurrent) { if (_concurrent) {
MutexLockerEx ml(_storage->_active_mutex, Mutex::_no_safepoint_check_flag); MutexLockerEx ml(_storage->_active_mutex, Mutex::_no_safepoint_check_flag);
assert(_storage->_concurrent_iteration_active != value, "precondition"); _storage->_concurrent_iteration_count += value;
_storage->_concurrent_iteration_active = value; assert(_storage->_concurrent_iteration_count >= 0, "invariant");
} }
} }
@ -954,7 +954,7 @@ void OopStorage::print_on(outputStream* st) const {
st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), " SIZE_FORMAT " bytes", st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), " SIZE_FORMAT " bytes",
name(), allocations, blocks, alloc_percentage, total_memory_usage()); name(), allocations, blocks, alloc_percentage, total_memory_usage());
if (_concurrent_iteration_active) { if (_concurrent_iteration_count > 0) {
st->print(", concurrent iteration active"); st->print(", concurrent iteration active");
} }
} }

View File

@ -220,7 +220,7 @@ private:
mutable SingleWriterSynchronizer _protect_active; mutable SingleWriterSynchronizer _protect_active;
// mutable because this gets set even for const iteration. // mutable because this gets set even for const iteration.
mutable bool _concurrent_iteration_active; mutable int _concurrent_iteration_count;
Block* find_block_or_null(const oop* ptr) const; Block* find_block_or_null(const oop* ptr) const;
void delete_empty_block(const Block& block); void delete_empty_block(const Block& block);

View File

@ -31,22 +31,16 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Support for parallel and optionally concurrent state iteration. // Support for parallel and optionally concurrent state iteration.
// //
// Parallel iteration is for the exclusive use of the GC. Other iteration
// clients must use serial iteration.
//
// Concurrent Iteration // Concurrent Iteration
// //
// Iteration involves the _active_array (an ActiveArray), which contains all // Iteration involves the _active_array (an ActiveArray), which contains all
// of the blocks owned by a storage object. // of the blocks owned by a storage object.
// //
// At most one concurrent ParState can exist at a time for a given storage // A concurrent ParState increments the associated storage's
// object. // _concurrent_iteration_count when the state is constructed, and
// // decrements it when the state is destroyed. These assignments are made with
// A concurrent ParState sets the associated storage's
// _concurrent_iteration_active flag true when the state is constructed, and
// sets it false when the state is destroyed. These assignments are made with
// _active_mutex locked. Meanwhile, empty block deletion is not done while // _active_mutex locked. Meanwhile, empty block deletion is not done while
// _concurrent_iteration_active is true. The flag check and the dependent // _concurrent_iteration_count is non-zero. The counter check and the dependent
// removal of a block from the _active_array is performed with _active_mutex // removal of a block from the _active_array is performed with _active_mutex
// locked. This prevents concurrent iteration and empty block deletion from // locked. This prevents concurrent iteration and empty block deletion from
// interfering with with each other. // interfering with with each other.
@ -83,8 +77,8 @@
// scheduling both operations to run at the same time. // scheduling both operations to run at the same time.
// //
// ParState<concurrent, is_const> // ParState<concurrent, is_const>
// concurrent must be true if iteration is concurrent with the // concurrent must be true if iteration may be concurrent with the
// mutator, false if iteration is at a safepoint. // mutators.
// //
// is_const must be true if the iteration is over a constant storage // is_const must be true if the iteration is over a constant storage
// object, false if the iteration may modify the storage object. // object, false if the iteration may modify the storage object.
@ -92,8 +86,7 @@
// ParState([const] OopStorage* storage) // ParState([const] OopStorage* storage)
// Construct an object for managing an iteration over storage. For a // Construct an object for managing an iteration over storage. For a
// concurrent ParState, empty block deletion for the associated storage // concurrent ParState, empty block deletion for the associated storage
// is inhibited for the life of the ParState. There can be no more // is inhibited for the life of the ParState.
// than one live concurrent ParState at a time for a given storage object.
// //
// template<typename F> void iterate(F f) // template<typename F> void iterate(F f)
// Repeatedly claims a block from the associated storage that has // Repeatedly claims a block from the associated storage that has
@ -152,7 +145,7 @@ class OopStorage::BasicParState {
struct IterationData; struct IterationData;
void update_iteration_state(bool value); void update_concurrent_iteration_count(int value);
bool claim_next_segment(IterationData* data); bool claim_next_segment(IterationData* data);
bool finish_iteration(const IterationData* data) const; bool finish_iteration(const IterationData* data) const;