8211718: Supporting multiple concurrent OopStorage iterators
Reviewed-by: pliden, kbarrett
This commit is contained in:
parent
90d6bbd01a
commit
b658954d7e
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user