8221360: Eliminate Shared_DirtyCardQ_lock

Reviewed-by: tschatzl, iwalulya
This commit is contained in:
Kim Barrett 2021-08-24 13:17:37 +00:00
parent 928b9724c9
commit 0597cde87d
9 changed files with 28 additions and 158 deletions

View File

@ -58,8 +58,7 @@ G1BarrierSet::G1BarrierSet(G1CardTable* card_table) :
_satb_mark_queue_buffer_allocator("SATB Buffer Allocator", G1SATBBufferSize),
_dirty_card_queue_buffer_allocator("DC Buffer Allocator", G1UpdateBufferSize),
_satb_mark_queue_set(&_satb_mark_queue_buffer_allocator),
_dirty_card_queue_set(&_dirty_card_queue_buffer_allocator),
_shared_dirty_card_queue(&_dirty_card_queue_set)
_dirty_card_queue_set(&_dirty_card_queue_buffer_allocator)
{}
void G1BarrierSet::enqueue(oop pre_val) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2021, 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,7 +27,6 @@
#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1SATBMarkQueueSet.hpp"
#include "gc/g1/g1SharedDirtyCardQueue.hpp"
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
@ -43,7 +42,6 @@ class G1BarrierSet: public CardTableBarrierSet {
BufferNode::Allocator _dirty_card_queue_buffer_allocator;
G1SATBMarkQueueSet _satb_mark_queue_set;
G1DirtyCardQueueSet _dirty_card_queue_set;
G1SharedDirtyCardQueue _shared_dirty_card_queue;
static G1BarrierSet* g1_barrier_set() {
return barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
@ -94,10 +92,6 @@ class G1BarrierSet: public CardTableBarrierSet {
return g1_barrier_set()->_dirty_card_queue_set;
}
static G1SharedDirtyCardQueue& shared_dirty_card_queue() {
return g1_barrier_set()->_shared_dirty_card_queue;
}
// Callbacks for runtime accesses.
template <DecoratorSet decorators, typename BarrierSetT = G1BarrierSet>
class AccessBarrier: public ModRefBarrierSet::AccessBarrier<decorators, BarrierSetT> {

View File

@ -546,8 +546,6 @@ void G1DirtyCardQueueSet::abandon_logs() {
}
} closure(*this);
Threads::threads_do(&closure);
G1BarrierSet::shared_dirty_card_queue().reset();
}
void G1DirtyCardQueueSet::concatenate_logs() {
@ -571,7 +569,6 @@ void G1DirtyCardQueueSet::concatenate_logs() {
} closure(*this);
Threads::threads_do(&closure);
G1BarrierSet::shared_dirty_card_queue().flush();
enqueue_all_paused_buffers();
verify_num_cards();
set_max_cards(old_limit);

View File

@ -41,7 +41,6 @@
#include "gc/g1/g1RootClosures.hpp"
#include "gc/g1/g1RemSet.hpp"
#include "gc/g1/g1ServiceThread.hpp"
#include "gc/g1/g1SharedDirtyCardQueue.hpp"
#include "gc/g1/g1_globals.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
@ -1688,12 +1687,27 @@ void G1RemSet::refine_card_concurrently(CardValue* const card_ptr,
return;
}
// Re-dirty the card and enqueue in the *shared* queue. Can't use
// the thread-local queue, because that might be the queue that is
// being processed by us; we could be a Java thread conscripted to
// perform refinement on our queue's current buffer.
enqueue_for_reprocessing(card_ptr);
}
// Re-dirty and re-enqueue the card to retry refinement later.
// This is used to deal with a rare race condition in concurrent refinement.
void G1RemSet::enqueue_for_reprocessing(CardValue* card_ptr) {
// We can't use the thread-local queue, because that might be the queue
// that is being processed by us; we could be a Java thread conscripted to
// perform refinement on our queue's current buffer. This situation only
// arises from rare race condition, so it's not worth any significant
// development effort or clever lock-free queue implementation. Instead
// we use brute force, allocating and enqueuing an entire buffer for just
// this card. Since buffers are processed in FIFO order and we try to
// keep some in the queue, it is likely that the racing state will have
// resolved by the time this card comes up for reprocessing.
*card_ptr = G1CardTable::dirty_card_val();
G1BarrierSet::shared_dirty_card_queue().enqueue(card_ptr);
G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
void** buffer = dcqs.allocate_buffer();
size_t index = dcqs.buffer_size() - 1;
buffer[index] = card_ptr;
dcqs.enqueue_completed_buffer(BufferNode::make_node_from_buffer(buffer, index));
}
void G1RemSet::print_periodic_summary_info(const char* header, uint period_count) {

View File

@ -57,6 +57,9 @@ class HeapRegionClaimer;
// external heap references into it. Uses a mod ref bs to track updates,
// so that they can be used to update the individual region remsets.
class G1RemSet: public CHeapObj<mtGC> {
public:
typedef CardTable::CardValue CardValue;
private:
G1RemSetScanState* _scan_state;
@ -72,10 +75,10 @@ private:
void print_merge_heap_roots_stats();
void assert_scan_top_is_null(uint hrm_index) NOT_DEBUG_RETURN;
void enqueue_for_reprocessing(CardValue* card_ptr);
public:
typedef CardTable::CardValue CardValue;
// Initialize data that depends on the heap size being known.
void initialize(uint max_reserved_regions);

View File

@ -1,73 +0,0 @@
/*
* Copyright (c) 2019, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1SharedDirtyCardQueue.hpp"
#include "gc/shared/ptrQueue.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
G1SharedDirtyCardQueue::G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset) :
_qset(qset),
_buffer(NULL),
_index(0)
{}
G1SharedDirtyCardQueue::~G1SharedDirtyCardQueue() {
flush();
}
void G1SharedDirtyCardQueue::enqueue(void* card_ptr) {
MutexLocker ml(Shared_DirtyCardQ_lock, Mutex::_no_safepoint_check_flag);
if (_index == 0) {
flush();
_buffer = _qset->allocate_buffer();
_index = _qset->buffer_size();
assert(_index != 0, "invariant");
}
_buffer[--_index] = card_ptr;
}
void G1SharedDirtyCardQueue::flush() {
if (_buffer != NULL) {
BufferNode* node = BufferNode::make_node_from_buffer(_buffer, _index);
_buffer = NULL;
_index = 0;
if (node->index() == _qset->buffer_size()) {
_qset->deallocate_buffer(node);
} else {
_qset->enqueue_completed_buffer(node);
}
}
assert(_index == 0, "invariant");
}
void G1SharedDirtyCardQueue::reset() {
if (_buffer == NULL) {
_index = 0;
} else {
_index = _qset->buffer_size();
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (c) 2019, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP
#define SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP
#include "utilities/globalDefinitions.hpp"
class G1DirtyCardQueueSet;
// A dirty card queue providing thread-safe enqueue. A shared global
// instance can be used for cases where a thread-local dirty card can't
// be used.
class G1SharedDirtyCardQueue {
G1DirtyCardQueueSet* const _qset;
void** _buffer;
size_t _index;
NONCOPYABLE(G1SharedDirtyCardQueue);
public:
G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset);
~G1SharedDirtyCardQueue(); // flushes the queue.
// Thread-safe addition to shared logging buffer.
void enqueue(void* card_ptr);
// Flush any pending entries to the qset and remove the buffer.
// Not thread-safe.
void flush();
// Discard any pending entries.
// Not thread-safe.
void reset();
};
#endif // SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP

View File

@ -74,7 +74,6 @@ Mutex* NonJavaThreadsListSync_lock = NULL;
Monitor* CGC_lock = NULL;
Monitor* STS_lock = NULL;
Monitor* G1OldGCCount_lock = NULL;
Mutex* Shared_DirtyCardQ_lock = NULL;
Mutex* G1DetachedRefinementStats_lock = NULL;
Mutex* MarkStackFreeList_lock = NULL;
Mutex* MarkStackChunkList_lock = NULL;
@ -217,8 +216,6 @@ void mutex_init() {
if (UseG1GC) {
def(G1OldGCCount_lock , PaddedMonitor, leaf, true, _safepoint_check_always);
def(Shared_DirtyCardQ_lock , PaddedMutex , access + 1, true, _safepoint_check_never);
def(G1DetachedRefinementStats_lock, PaddedMutex, leaf , true, _safepoint_check_never);
def(FreeList_lock , PaddedMutex , leaf , true, _safepoint_check_never);

View File

@ -68,9 +68,6 @@ extern Monitor* CGC_lock; // used for coordination betwee
// fore- & background GC threads.
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
extern Monitor* G1OldGCCount_lock; // in support of "concurrent" full gc
extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card
// queue shared by
// non-Java threads.
extern Mutex* G1DetachedRefinementStats_lock; // Lock protecting detached refinement stats
extern Mutex* MarkStackFreeList_lock; // Protects access to the global mark stack free list.
extern Mutex* MarkStackChunkList_lock; // Protects access to the global mark stack chunk list.