8221361: Eliminate two-phase initialization for PtrQueueSet classes

Move allocator and CBL monitor init to constructor.

Reviewed-by: tschatzl, shade
This commit is contained in:
Kim Barrett 2019-09-09 16:54:48 -04:00
parent ea0fbbca51
commit 8b67b75f50
17 changed files with 57 additions and 133 deletions

View file

@ -57,8 +57,8 @@ G1BarrierSet::G1BarrierSet(G1CardTable* card_table) :
BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)), BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)),
_satb_mark_queue_buffer_allocator("SATB Buffer Allocator", G1SATBBufferSize), _satb_mark_queue_buffer_allocator("SATB Buffer Allocator", G1SATBBufferSize),
_dirty_card_queue_buffer_allocator("DC Buffer Allocator", G1UpdateBufferSize), _dirty_card_queue_buffer_allocator("DC Buffer Allocator", G1UpdateBufferSize),
_satb_mark_queue_set(), _satb_mark_queue_set(&_satb_mark_queue_buffer_allocator),
_dirty_card_queue_set(), _dirty_card_queue_set(DirtyCardQ_CBL_mon, &_dirty_card_queue_buffer_allocator),
_shared_dirty_card_queue(&_dirty_card_queue_set) _shared_dirty_card_queue(&_dirty_card_queue_set)
{} {}
@ -159,11 +159,3 @@ void G1BarrierSet::on_thread_detach(Thread* thread) {
G1ThreadLocalData::satb_mark_queue(thread).flush(); G1ThreadLocalData::satb_mark_queue(thread).flush();
G1ThreadLocalData::dirty_card_queue(thread).flush(); G1ThreadLocalData::dirty_card_queue(thread).flush();
} }
BufferNode::Allocator& G1BarrierSet::satb_mark_queue_buffer_allocator() {
return _satb_mark_queue_buffer_allocator;
}
BufferNode::Allocator& G1BarrierSet::dirty_card_queue_buffer_allocator() {
return _dirty_card_queue_buffer_allocator;
}

View file

@ -82,9 +82,6 @@ class G1BarrierSet: public CardTableBarrierSet {
virtual void on_thread_attach(Thread* thread); virtual void on_thread_attach(Thread* thread);
virtual void on_thread_detach(Thread* thread); virtual void on_thread_detach(Thread* thread);
BufferNode::Allocator& satb_mark_queue_buffer_allocator();
BufferNode::Allocator& dirty_card_queue_buffer_allocator();
static G1SATBMarkQueueSet& satb_mark_queue_set() { static G1SATBMarkQueueSet& satb_mark_queue_set() {
return g1_barrier_set()->_satb_mark_queue_set; return g1_barrier_set()->_satb_mark_queue_set;
} }

View file

@ -1678,15 +1678,11 @@ jint G1CollectedHeap::initialize() {
BarrierSet::set_barrier_set(bs); BarrierSet::set_barrier_set(bs);
_card_table = ct; _card_table = ct;
G1BarrierSet::satb_mark_queue_set().initialize(this, {
&bs->satb_mark_queue_buffer_allocator(), G1SATBMarkQueueSet& satbqs = bs->satb_mark_queue_set();
G1SATBProcessCompletedThreshold, satbqs.set_process_completed_buffers_threshold(G1SATBProcessCompletedThreshold);
G1SATBBufferEnqueueingThresholdPercent); satbqs.set_buffer_enqueue_threshold_percentage(G1SATBBufferEnqueueingThresholdPercent);
}
// process_cards_threshold and max_cards are updated
// later, based on the concurrent refinement object.
G1BarrierSet::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
&bs->dirty_card_queue_buffer_allocator());
// Create the hot card cache. // Create the hot card cache.
_hot_card_cache = new G1HotCardCache(this); _hot_card_cache = new G1HotCardCache(this);

View file

@ -62,9 +62,10 @@ void G1DirtyCardQueue::handle_completed_buffer() {
} }
} }
G1DirtyCardQueueSet::G1DirtyCardQueueSet() : G1DirtyCardQueueSet::G1DirtyCardQueueSet(Monitor* cbl_mon,
PtrQueueSet(), BufferNode::Allocator* allocator) :
_cbl_mon(NULL), PtrQueueSet(allocator),
_cbl_mon(cbl_mon),
_completed_buffers_head(NULL), _completed_buffers_head(NULL),
_completed_buffers_tail(NULL), _completed_buffers_tail(NULL),
_num_cards(0), _num_cards(0),
@ -88,13 +89,6 @@ uint G1DirtyCardQueueSet::num_par_ids() {
return (uint)os::initial_active_processor_count(); return (uint)os::initial_active_processor_count();
} }
void G1DirtyCardQueueSet::initialize(Monitor* cbl_mon,
BufferNode::Allocator* allocator) {
PtrQueueSet::initialize(allocator);
assert(_cbl_mon == NULL, "Init order issue?");
_cbl_mon = cbl_mon;
}
void G1DirtyCardQueueSet::handle_zero_index_for_thread(Thread* t) { void G1DirtyCardQueueSet::handle_zero_index_for_thread(Thread* t) {
G1ThreadLocalData::dirty_card_queue(t).handle_zero_index(); G1ThreadLocalData::dirty_card_queue(t).handle_zero_index();
} }

View file

@ -103,11 +103,9 @@ class G1DirtyCardQueueSet: public PtrQueueSet {
jint _processed_buffers_rs_thread; jint _processed_buffers_rs_thread;
public: public:
G1DirtyCardQueueSet(); G1DirtyCardQueueSet(Monitor* cbl_mon, BufferNode::Allocator* allocator);
~G1DirtyCardQueueSet(); ~G1DirtyCardQueueSet();
void initialize(Monitor* cbl_mon, BufferNode::Allocator* allocator);
// The number of parallel ids that can be claimed to allow collector or // The number of parallel ids that can be claimed to allow collector or
// mutator threads to do card-processing work. // mutator threads to do card-processing work.
static uint num_par_ids(); static uint num_par_ids();

View file

@ -31,12 +31,10 @@
// G1RedirtyCardsQueueBase::LocalQSet // G1RedirtyCardsQueueBase::LocalQSet
G1RedirtyCardsQueueBase::LocalQSet::LocalQSet(G1RedirtyCardsQueueSet* shared_qset) : G1RedirtyCardsQueueBase::LocalQSet::LocalQSet(G1RedirtyCardsQueueSet* shared_qset) :
PtrQueueSet(), PtrQueueSet(shared_qset->allocator()),
_shared_qset(shared_qset), _shared_qset(shared_qset),
_buffers() _buffers()
{ {}
PtrQueueSet::initialize(_shared_qset->allocator());
}
G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() { G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() {
assert(_buffers._head == NULL, "unflushed qset"); assert(_buffers._head == NULL, "unflushed qset");
@ -86,14 +84,12 @@ void G1RedirtyCardsQueue::flush() {
// G1RedirtyCardsQueueSet // G1RedirtyCardsQueueSet
G1RedirtyCardsQueueSet::G1RedirtyCardsQueueSet(BufferNode::Allocator* allocator) : G1RedirtyCardsQueueSet::G1RedirtyCardsQueueSet(BufferNode::Allocator* allocator) :
PtrQueueSet(), PtrQueueSet(allocator),
_list(), _list(),
_entry_count(0), _entry_count(0),
_tail(NULL) _tail(NULL)
DEBUG_ONLY(COMMA _collecting(true)) DEBUG_ONLY(COMMA _collecting(true))
{ {}
initialize(allocator);
}
G1RedirtyCardsQueueSet::~G1RedirtyCardsQueueSet() { G1RedirtyCardsQueueSet::~G1RedirtyCardsQueueSet() {
verify_empty(); verify_empty();

View file

@ -32,17 +32,9 @@
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
G1SATBMarkQueueSet::G1SATBMarkQueueSet() : _g1h(NULL) {} G1SATBMarkQueueSet::G1SATBMarkQueueSet(BufferNode::Allocator* allocator) :
SATBMarkQueueSet(allocator)
void G1SATBMarkQueueSet::initialize(G1CollectedHeap* g1h, {}
BufferNode::Allocator* allocator,
size_t process_completed_buffers_threshold,
uint buffer_enqueue_threshold_percentage) {
SATBMarkQueueSet::initialize(allocator,
process_completed_buffers_threshold,
buffer_enqueue_threshold_percentage);
_g1h = g1h;
}
void G1SATBMarkQueueSet::handle_zero_index_for_thread(Thread* t) { void G1SATBMarkQueueSet::handle_zero_index_for_thread(Thread* t) {
G1ThreadLocalData::satb_mark_queue(t).handle_zero_index(); G1ThreadLocalData::satb_mark_queue(t).handle_zero_index();
@ -112,7 +104,7 @@ class G1SATBMarkQueueFilterFn {
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
public: public:
G1SATBMarkQueueFilterFn(G1CollectedHeap* g1h) : _g1h(g1h) {} G1SATBMarkQueueFilterFn() : _g1h(G1CollectedHeap::heap()) {}
// Return true if entry should be filtered out (removed), false if // Return true if entry should be filtered out (removed), false if
// it should be retained. // it should be retained.
@ -122,6 +114,5 @@ public:
}; };
void G1SATBMarkQueueSet::filter(SATBMarkQueue* queue) { void G1SATBMarkQueueSet::filter(SATBMarkQueue* queue) {
assert(_g1h != NULL, "SATB queue set not initialized"); apply_filter(G1SATBMarkQueueFilterFn(), queue);
apply_filter(G1SATBMarkQueueFilterFn(_g1h), queue);
} }

View file

@ -35,12 +35,7 @@ class G1SATBMarkQueueSet : public SATBMarkQueueSet {
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
public: public:
G1SATBMarkQueueSet(); G1SATBMarkQueueSet(BufferNode::Allocator* allocator);
void initialize(G1CollectedHeap* g1h,
BufferNode::Allocator* allocator,
size_t process_completed_buffers_threshold,
uint buffer_enqueue_threshold_percentage);
static void handle_zero_index_for_thread(Thread* t); static void handle_zero_index_for_thread(Thread* t);
virtual SATBMarkQueue& satb_queue_for_thread(Thread* const t) const; virtual SATBMarkQueue& satb_queue_for_thread(Thread* const t) const;

View file

@ -40,7 +40,7 @@ PtrQueue::PtrQueue(PtrQueueSet* qset, bool active) :
_qset(qset), _qset(qset),
_active(active), _active(active),
_index(0), _index(0),
_capacity_in_bytes(0), _capacity_in_bytes(index_to_byte_index(qset->buffer_size())),
_buf(NULL) _buf(NULL)
{} {}
@ -80,13 +80,6 @@ void PtrQueue::handle_zero_index() {
if (_buf != NULL) { if (_buf != NULL) {
handle_completed_buffer(); handle_completed_buffer();
} else { } else {
// Bootstrapping kludge; lazily initialize capacity. The initial
// thread's queues are constructed before the second phase of the
// two-phase initialization of the associated qsets. As a result,
// we can't initialize _capacity_in_bytes in the queue constructor.
if (_capacity_in_bytes == 0) {
_capacity_in_bytes = index_to_byte_index(qset()->buffer_size());
}
allocate_buffer(); allocate_buffer();
} }
} }
@ -250,18 +243,13 @@ size_t BufferNode::Allocator::reduce_free_list(size_t remove_goal) {
return removed; return removed;
} }
PtrQueueSet::PtrQueueSet() : PtrQueueSet::PtrQueueSet(BufferNode::Allocator* allocator) :
_allocator(NULL), _allocator(allocator),
_all_active(false) _all_active(false)
{} {}
PtrQueueSet::~PtrQueueSet() {} PtrQueueSet::~PtrQueueSet() {}
void PtrQueueSet::initialize(BufferNode::Allocator* allocator) {
assert(allocator != NULL, "Init order issue?");
_allocator = allocator;
}
void** PtrQueueSet::allocate_buffer() { void** PtrQueueSet::allocate_buffer() {
BufferNode* node = _allocator->allocate(); BufferNode* node = _allocator->allocate();
return BufferNode::make_buffer_from_node(node); return BufferNode::make_buffer_from_node(node);

View file

@ -303,13 +303,9 @@ protected:
bool _all_active; bool _all_active;
// Create an empty ptr queue set. // Create an empty ptr queue set.
PtrQueueSet(); PtrQueueSet(BufferNode::Allocator* allocator);
~PtrQueueSet(); ~PtrQueueSet();
// Because of init-order concerns, we can't pass these as constructor
// arguments.
void initialize(BufferNode::Allocator* allocator);
public: public:
// Return the associated BufferNode allocator. // Return the associated BufferNode allocator.

View file

@ -108,8 +108,8 @@ void SATBMarkQueue::print(const char* name) {
#endif // PRODUCT #endif // PRODUCT
SATBMarkQueueSet::SATBMarkQueueSet() : SATBMarkQueueSet::SATBMarkQueueSet(BufferNode::Allocator* allocator) :
PtrQueueSet(), PtrQueueSet(allocator),
_list(), _list(),
_count_and_process_flag(0), _count_and_process_flag(0),
_process_completed_buffers_threshold(SIZE_MAX), _process_completed_buffers_threshold(SIZE_MAX),
@ -153,27 +153,21 @@ static void decrement_count(volatile size_t* cfptr) {
} while (value != old); } while (value != old);
} }
// Scale requested threshold to align with count field. If scaling void SATBMarkQueueSet::set_process_completed_buffers_threshold(size_t value) {
// overflows, just use max value. Set process flag field to make // Scale requested threshold to align with count field. If scaling
// comparison in increment_count exact. // overflows, just use max value. Set process flag field to make
static size_t scale_threshold(size_t value) { // comparison in increment_count exact.
size_t scaled_value = value << 1; size_t scaled_value = value << 1;
if ((scaled_value >> 1) != value) { if ((scaled_value >> 1) != value) {
scaled_value = SIZE_MAX; scaled_value = SIZE_MAX;
} }
return scaled_value | 1; _process_completed_buffers_threshold = scaled_value | 1;
} }
void SATBMarkQueueSet::initialize(BufferNode::Allocator* allocator, void SATBMarkQueueSet::set_buffer_enqueue_threshold_percentage(uint value) {
size_t process_completed_buffers_threshold,
uint buffer_enqueue_threshold_percentage) {
PtrQueueSet::initialize(allocator);
_process_completed_buffers_threshold =
scale_threshold(process_completed_buffers_threshold);
assert(buffer_size() != 0, "buffer size not initialized");
// Minimum threshold of 1 ensures enqueuing of completely full buffers. // Minimum threshold of 1 ensures enqueuing of completely full buffers.
size_t size = buffer_size(); size_t size = buffer_size();
size_t enqueue_qty = (size * buffer_enqueue_threshold_percentage) / 100; size_t enqueue_qty = (size * value) / 100;
_buffer_enqueue_threshold = MAX2(size - enqueue_qty, (size_t)1); _buffer_enqueue_threshold = MAX2(size - enqueue_qty, (size_t)1);
} }

View file

@ -112,7 +112,7 @@ class SATBMarkQueueSet: public PtrQueueSet {
#endif // ASSERT #endif // ASSERT
protected: protected:
SATBMarkQueueSet(); SATBMarkQueueSet(BufferNode::Allocator* allocator);
~SATBMarkQueueSet(); ~SATBMarkQueueSet();
template<typename Filter> template<typename Filter>
@ -120,10 +120,6 @@ protected:
queue->apply_filter(filter); queue->apply_filter(filter);
} }
void initialize(BufferNode::Allocator* allocator,
size_t process_completed_buffers_threshold,
uint buffer_enqueue_threshold_percentage);
public: public:
virtual SATBMarkQueue& satb_queue_for_thread(Thread* const t) const = 0; virtual SATBMarkQueue& satb_queue_for_thread(Thread* const t) const = 0;
@ -133,7 +129,11 @@ public:
// set itself, has an active value same as expected_active. // set itself, has an active value same as expected_active.
void set_active_all_threads(bool active, bool expected_active); void set_active_all_threads(bool active, bool expected_active);
void set_process_completed_buffers_threshold(size_t value);
size_t buffer_enqueue_threshold() const { return _buffer_enqueue_threshold; } size_t buffer_enqueue_threshold() const { return _buffer_enqueue_threshold; }
void set_buffer_enqueue_threshold_percentage(uint value);
virtual void filter(SATBMarkQueue* queue) = 0; virtual void filter(SATBMarkQueue* queue) = 0;
// If there exists some completed buffer, pop and process it, and // If there exists some completed buffer, pop and process it, and

View file

@ -75,7 +75,8 @@ ShenandoahBarrierSet::ShenandoahBarrierSet(ShenandoahHeap* heap) :
NULL /* barrier_set_nmethod */, NULL /* barrier_set_nmethod */,
BarrierSet::FakeRtti(BarrierSet::ShenandoahBarrierSet)), BarrierSet::FakeRtti(BarrierSet::ShenandoahBarrierSet)),
_heap(heap), _heap(heap),
_satb_mark_queue_set() _satb_mark_queue_buffer_allocator("SATB Buffer Allocator", ShenandoahSATBBufferSize),
_satb_mark_queue_set(&_satb_mark_queue_buffer_allocator)
{ {
} }

View file

@ -41,6 +41,7 @@ public:
private: private:
ShenandoahHeap* _heap; ShenandoahHeap* _heap;
BufferNode::Allocator _satb_mark_queue_buffer_allocator;
ShenandoahSATBMarkQueueSet _satb_mark_queue_set; ShenandoahSATBMarkQueueSet _satb_mark_queue_set;
public: public:

View file

@ -343,11 +343,13 @@ jint ShenandoahHeap::initialize() {
Copy::fill_to_bytes(_liveness_cache[worker], _num_regions * sizeof(jushort)); Copy::fill_to_bytes(_liveness_cache[worker], _num_regions * sizeof(jushort));
} }
// The call below uses stuff (the SATB* things) that are in G1, but probably // There should probably be Shenandoah-specific options for these,
// belong into a shared location. // just as there are G1-specific options.
ShenandoahBarrierSet::satb_mark_queue_set().initialize(this, {
20 /* G1SATBProcessCompletedThreshold */, ShenandoahSATBMarkQueueSet& satbqs = ShenandoahBarrierSet::satb_mark_queue_set();
60 /* G1SATBBufferEnqueueingThresholdPercent */); satbqs.set_process_completed_buffers_threshold(20); // G1SATBProcessCompletedThreshold
satbqs.set_buffer_enqueue_threshold_percentage(60); // G1SATBBufferEnqueueingThresholdPercent
}
_monitoring_support = new ShenandoahMonitoringSupport(this); _monitoring_support = new ShenandoahMonitoringSupport(this);
_phase_timings = new ShenandoahPhaseTimings(); _phase_timings = new ShenandoahPhaseTimings();

View file

@ -27,20 +27,10 @@
#include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp" #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp"
#include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
ShenandoahSATBMarkQueueSet::ShenandoahSATBMarkQueueSet() : ShenandoahSATBMarkQueueSet::ShenandoahSATBMarkQueueSet(BufferNode::Allocator* allocator) :
_heap(NULL), SATBMarkQueueSet(allocator)
_satb_mark_queue_buffer_allocator("SATB Buffer Allocator", ShenandoahSATBBufferSize)
{} {}
void ShenandoahSATBMarkQueueSet::initialize(ShenandoahHeap* const heap,
int process_completed_threshold,
uint buffer_enqueue_threshold_percentage) {
SATBMarkQueueSet::initialize(&_satb_mark_queue_buffer_allocator,
process_completed_threshold,
buffer_enqueue_threshold_percentage);
_heap = heap;
}
SATBMarkQueue& ShenandoahSATBMarkQueueSet::satb_queue_for_thread(Thread* const t) const { SATBMarkQueue& ShenandoahSATBMarkQueueSet::satb_queue_for_thread(Thread* const t) const {
return ShenandoahThreadLocalData::satb_mark_queue(t); return ShenandoahThreadLocalData::satb_mark_queue(t);
} }
@ -60,11 +50,11 @@ public:
}; };
void ShenandoahSATBMarkQueueSet::filter(SATBMarkQueue* queue) { void ShenandoahSATBMarkQueueSet::filter(SATBMarkQueue* queue) {
assert(_heap != NULL, "SATB queue set not initialized"); ShenandoahHeap* heap = ShenandoahHeap::heap();
if (_heap->has_forwarded_objects()) { if (heap->has_forwarded_objects()) {
apply_filter(ShenandoahSATBMarkQueueFilterFn<true>(_heap), queue); apply_filter(ShenandoahSATBMarkQueueFilterFn<true>(heap), queue);
} else { } else {
apply_filter(ShenandoahSATBMarkQueueFilterFn<false>(_heap), queue); apply_filter(ShenandoahSATBMarkQueueFilterFn<false>(heap), queue);
} }
} }

View file

@ -37,15 +37,8 @@ public:
}; };
class ShenandoahSATBMarkQueueSet : public SATBMarkQueueSet { class ShenandoahSATBMarkQueueSet : public SATBMarkQueueSet {
private:
ShenandoahHeap* _heap;
BufferNode::Allocator _satb_mark_queue_buffer_allocator;
public: public:
ShenandoahSATBMarkQueueSet(); ShenandoahSATBMarkQueueSet(BufferNode::Allocator* allocator);
void initialize(ShenandoahHeap* const heap,
int process_completed_threshold,
uint buffer_enqueue_threshold_percentage);
virtual SATBMarkQueue& satb_queue_for_thread(Thread* const t) const; virtual SATBMarkQueue& satb_queue_for_thread(Thread* const t) const;
virtual void filter(SATBMarkQueue* queue); virtual void filter(SATBMarkQueue* queue);