8258142: Simplify G1RedirtyCardsQueue

Separate local redirty qset from redirty queue.

Reviewed-by: tschatzl, iwalulya
This commit is contained in:
Kim Barrett 2020-12-14 16:13:23 +00:00
parent e8c40bafa5
commit 1ff0f1673d
5 changed files with 47 additions and 63 deletions

View File

@ -199,6 +199,7 @@ class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
uint _worker_id;
G1RedirtyCardsLocalQueueSet _rdc_local_qset;
G1RedirtyCardsQueue _rdcq;
UpdateLogBuffersDeferred _log_buffer_cl;
@ -206,10 +207,16 @@ public:
RemoveSelfForwardPtrHRClosure(G1RedirtyCardsQueueSet* rdcqs, uint worker_id) :
_g1h(G1CollectedHeap::heap()),
_worker_id(worker_id),
_rdcq(rdcqs),
_rdc_local_qset(rdcqs),
_rdcq(&_rdc_local_qset),
_log_buffer_cl(&_rdcq) {
}
~RemoveSelfForwardPtrHRClosure() {
_rdcq.flush();
_rdc_local_qset.flush();
}
size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr,
bool during_concurrent_start) {
RemoveSelfForwardPtrObjClosure rspc(hr,

View File

@ -58,7 +58,8 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
size_t optional_cset_length)
: _g1h(g1h),
_task_queue(g1h->task_queue(worker_id)),
_rdcq(rdcqs),
_rdc_local_qset(rdcqs),
_rdcq(&_rdc_local_qset),
_ct(g1h->card_table()),
_closures(NULL),
_plab_allocator(NULL),
@ -114,6 +115,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
size_t G1ParScanThreadState::flush(size_t* surviving_young_words) {
_rdcq.flush();
_rdc_local_qset.flush();
flush_numa_stats();
// Update allocation statistics.
_plab_allocator->flush_and_retire_stats();

View File

@ -48,6 +48,7 @@ class outputStream;
class G1ParScanThreadState : public CHeapObj<mtGC> {
G1CollectedHeap* _g1h;
G1ScannerTasksQueue* _task_queue;
G1RedirtyCardsLocalQueueSet _rdc_local_qset;
G1RedirtyCardsQueue _rdcq;
G1CardTable* _ct;
G1EvacuationRootClosures* _closures;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,19 +30,21 @@
// G1RedirtyCardsQueueBase::LocalQSet
G1RedirtyCardsQueueBase::LocalQSet::LocalQSet(G1RedirtyCardsQueueSet* shared_qset) :
G1RedirtyCardsLocalQueueSet::G1RedirtyCardsLocalQueueSet(G1RedirtyCardsQueueSet* shared_qset) :
PtrQueueSet(shared_qset->allocator()),
_shared_qset(shared_qset),
_buffers()
{}
G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() {
#ifdef ASSERT
G1RedirtyCardsLocalQueueSet::~G1RedirtyCardsLocalQueueSet() {
assert(_buffers._head == NULL, "unflushed qset");
assert(_buffers._tail == NULL, "invariant");
assert(_buffers._entry_count == 0, "invariant");
}
#endif // ASSERT
void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* node) {
void G1RedirtyCardsLocalQueueSet::enqueue_completed_buffer(BufferNode* node) {
_buffers._entry_count += buffer_size() - node->index();
node->set_next(_buffers._head);
_buffers._head = node;
@ -51,26 +53,22 @@ void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* no
}
}
G1BufferNodeList G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
G1BufferNodeList result = _buffers;
void G1RedirtyCardsLocalQueueSet::flush() {
_shared_qset->add_bufferlist(_buffers);
_buffers = G1BufferNodeList();
return result;
}
void G1RedirtyCardsQueueBase::LocalQSet::flush() {
_shared_qset->merge_bufferlist(this);
}
// G1RedirtyCardsQueue
G1RedirtyCardsQueue::G1RedirtyCardsQueue(G1RedirtyCardsQueueSet* qset) :
G1RedirtyCardsQueueBase(qset), // Init _local_qset before passing to PtrQueue.
PtrQueue(&_local_qset, true /* active (always) */)
G1RedirtyCardsQueue::G1RedirtyCardsQueue(G1RedirtyCardsLocalQueueSet* qset) :
PtrQueue(qset, true /* always active */)
{}
#ifdef ASSERT
G1RedirtyCardsQueue::~G1RedirtyCardsQueue() {
flush();
assert(is_empty(), "unflushed queue");
}
#endif // ASSERT
void G1RedirtyCardsQueue::handle_completed_buffer() {
enqueue_completed_buffer();
@ -78,7 +76,6 @@ void G1RedirtyCardsQueue::handle_completed_buffer() {
void G1RedirtyCardsQueue::flush() {
flush_impl();
_local_qset.flush();
}
// G1RedirtyCardsQueueSet
@ -134,13 +131,12 @@ void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) {
update_tail(node);
}
void G1RedirtyCardsQueueSet::merge_bufferlist(LocalQSet* src) {
void G1RedirtyCardsQueueSet::add_bufferlist(const G1BufferNodeList& buffers) {
assert(_collecting, "precondition");
const G1BufferNodeList from = src->take_all_completed_buffers();
if (from._head != NULL) {
assert(from._tail != NULL, "invariant");
Atomic::add(&_entry_count, from._entry_count);
_list.prepend(*from._head, *from._tail);
update_tail(from._tail);
if (buffers._head != NULL) {
assert(buffers._tail != NULL, "invariant");
Atomic::add(&_entry_count, buffers._entry_count);
_list.prepend(*buffers._head, *buffers._tail);
update_tail(buffers._tail);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,56 +27,36 @@
#include "gc/g1/g1BufferNodeList.hpp"
#include "gc/shared/ptrQueue.hpp"
#include "memory/allocation.hpp"
#include "memory/padded.hpp"
class G1CardTableEntryClosure;
class G1RedirtyCardsQueue;
class G1RedirtyCardsQueueSet;
// Provide G1RedirtyCardsQueue with a thread-local qset. It provides an
// uncontended staging area for completed buffers, to be flushed to the
// shared qset en masse. Using the "base from member" idiom so the local
// qset is constructed before being passed to the PtrQueue constructor.
class G1RedirtyCardsQueueBase {
friend class G1RedirtyCardsQueue;
friend class G1RedirtyCardsQueueSet;
class LocalQSet : public PtrQueueSet {
// shared qset en masse.
class G1RedirtyCardsLocalQueueSet : public PtrQueueSet {
G1RedirtyCardsQueueSet* _shared_qset;
G1BufferNodeList _buffers;
public:
LocalQSet(G1RedirtyCardsQueueSet* shared_qset);
~LocalQSet();
public:
G1RedirtyCardsLocalQueueSet(G1RedirtyCardsQueueSet* shared_qset);
~G1RedirtyCardsLocalQueueSet() NOT_DEBUG(= default);
// Add the buffer to the local list.
virtual void enqueue_completed_buffer(BufferNode* node);
// Transfer all completed buffers to the shared qset.
void flush();
G1BufferNodeList take_all_completed_buffers();
};
G1RedirtyCardsQueueBase(G1RedirtyCardsQueueSet* shared_qset) :
_local_qset(shared_qset) {}
~G1RedirtyCardsQueueBase() {}
LocalQSet _local_qset;
};
// Worker-local queues of card table entries.
class G1RedirtyCardsQueue : private G1RedirtyCardsQueueBase, public PtrQueue {
class G1RedirtyCardsQueue : public PtrQueue {
protected:
virtual void handle_completed_buffer();
public:
G1RedirtyCardsQueue(G1RedirtyCardsQueueSet* qset);
// Flushes the queue.
~G1RedirtyCardsQueue();
G1RedirtyCardsQueue(G1RedirtyCardsLocalQueueSet* qset);
~G1RedirtyCardsQueue() NOT_DEBUG(= default);
// Flushes all enqueued cards to qset.
void flush();
@ -97,8 +77,6 @@ class G1RedirtyCardsQueueSet : public PtrQueueSet {
BufferNode* _tail;
DEBUG_ONLY(mutable bool _collecting;)
typedef G1RedirtyCardsQueueBase::LocalQSet LocalQSet;
void update_tail(BufferNode* node);
public:
@ -110,7 +88,7 @@ public:
// Collect buffers. These functions are thread-safe.
// precondition: Must not be concurrent with buffer processing.
virtual void enqueue_completed_buffer(BufferNode* node);
void merge_bufferlist(LocalQSet* src);
void add_bufferlist(const G1BufferNodeList& buffers);
// Processing phase operations.
// precondition: Must not be concurrent with buffer collection.