diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 2761b9513949b..3bb42433cd61c 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -66,6 +66,8 @@ static const ZStatSubPhase ZSubPhaseConcurrentMarkTryFlush("Concurrent Mark Try static const ZStatSubPhase ZSubPhaseConcurrentMarkTryTerminate("Concurrent Mark Try Terminate"); static const ZStatSubPhase ZSubPhaseMarkTryComplete("Pause Mark Try Complete"); +volatile bool ZMark::_push_local_stripe = false; + ZMark::ZMark(ZWorkers* workers, ZPageTable* page_table) : _workers(workers), _page_table(page_table), @@ -117,6 +119,8 @@ void ZMark::start() { const size_t nstripes = calculate_nstripes(_nworkers); _stripes.set_nstripes(nstripes); + _push_local_stripe = false; + // Update statistics ZStatMark::set_at_mark_start(nstripes); @@ -157,7 +161,9 @@ bool ZMark::is_array(uintptr_t addr) const { void ZMark::push_partial_array(uintptr_t addr, size_t size, bool finalizable) { assert(is_aligned(addr, ZMarkPartialArrayMinSize), "Address misaligned"); ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current()); - ZMarkStripe* const stripe = _stripes.stripe_for_addr(addr); + ZMarkStripe* const stripe = push_local_stripe() ? + _stripes.stripe_for_worker(_nworkers, ZThread::worker_id()) : + _stripes.stripe_for_addr(addr); const uintptr_t offset = ZAddress::offset(addr) >> ZMarkPartialArrayMinSizeShift; const uintptr_t length = size / oopSize; const ZMarkStackEntry entry(offset, length, finalizable); diff --git a/src/hotspot/share/gc/z/zMark.hpp b/src/hotspot/share/gc/z/zMark.hpp index 9711899e89bfe..58955b6aa917c 100644 --- a/src/hotspot/share/gc/z/zMark.hpp +++ b/src/hotspot/share/gc/z/zMark.hpp @@ -53,6 +53,7 @@ class ZMark { size_t _ntrycomplete; size_t _ncontinue; uint _nworkers; + static volatile bool _push_local_stripe; size_t calculate_nstripes(uint nworkers) const; @@ -109,6 +110,13 @@ class ZMark { void mark(bool initial); bool end(); + static void set_push_local_stripe(bool mode) { + Atomic::store(&_push_local_stripe, mode); + } + static bool push_local_stripe() { + return Atomic::load(&_push_local_stripe); + } + void flush_and_free(); bool flush_and_free(Thread* thread); }; diff --git a/src/hotspot/share/gc/z/zMark.inline.hpp b/src/hotspot/share/gc/z/zMark.inline.hpp index 95f1e336a378b..17cf017945f00 100644 --- a/src/hotspot/share/gc/z/zMark.inline.hpp +++ b/src/hotspot/share/gc/z/zMark.inline.hpp @@ -28,6 +28,7 @@ #include "gc/z/zMark.hpp" #include "gc/z/zMarkStack.inline.hpp" #include "gc/z/zThreadLocalData.hpp" +#include "gc/z/zThread.inline.hpp" #include "runtime/thread.hpp" #include "utilities/debug.hpp" @@ -35,7 +36,9 @@ template <bool follow, bool finalizable, bool publish> inline void ZMark::mark_object(uintptr_t addr) { assert(ZAddress::is_marked(addr), "Should be marked"); ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current()); - ZMarkStripe* const stripe = _stripes.stripe_for_addr(addr); + ZMarkStripe* const stripe = push_local_stripe() && ZThread::is_worker() ? + _stripes.stripe_for_worker(_nworkers, ZThread::worker_id()) : + _stripes.stripe_for_addr(addr); ZMarkStackEntry entry(addr, follow, finalizable); stacks->push(&_allocator, &_stripes, stripe, entry, publish); diff --git a/src/hotspot/share/gc/z/zMarkStackAllocator.cpp b/src/hotspot/share/gc/z/zMarkStackAllocator.cpp index 2c3feabe105f1..3bdaa9910bed0 100644 --- a/src/hotspot/share/gc/z/zMarkStackAllocator.cpp +++ b/src/hotspot/share/gc/z/zMarkStackAllocator.cpp @@ -27,6 +27,7 @@ #include "gc/z/zLock.inline.hpp" #include "gc/z/zMarkStack.inline.hpp" #include "gc/z/zMarkStackAllocator.hpp" +#include "gc/z/zMark.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" @@ -128,7 +129,8 @@ uintptr_t ZMarkStackSpace::alloc(size_t size) { ZMarkStackAllocator::ZMarkStackAllocator() : _freelist(), - _space() { + _space(), + _nmagazine(0) { // Prime free list to avoid an immediate space // expansion when marking starts. if (_space.is_initialized()) { @@ -159,13 +161,45 @@ ZMarkStackMagazine* ZMarkStackAllocator::create_magazine_from_space(uintptr_t ad assert(success, "Magazine should never get full"); } + inc_nmagazine(); + return magazine; } +void ZMarkStackAllocator::inc_nmagazine() { + int cur = Atomic::add(&_nmagazine, 1); + if (!ZMark::push_local_stripe() && + cur * ZMarkStackMagazineSize >= ZMarkStackSpaceLimit * ZStackModeChangeRatio) { + ZMark::set_push_local_stripe(true); + } +} + +void ZMarkStackAllocator::dec_nmagazine() { + int nmagazine = Atomic::load(&_nmagazine); + + for (;;) { + if (nmagazine == 0) { + break; + } + const int new_nmagazine = nmagazine - 1; + const int prev_nmagazine = Atomic::cmpxchg(&_nmagazine, nmagazine, new_nmagazine); + if (prev_nmagazine == nmagazine) { + break; + } + nmagazine = prev_nmagazine; + } + + if (ZMark::push_local_stripe() && + nmagazine * ZMarkStackMagazineSize * 2.0 < ZMarkStackSpaceLimit * ZStackModeChangeRatio) { + ZMark::set_push_local_stripe(false); + } +} + ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() { // Try allocating from the free list first ZMarkStackMagazine* const magazine = _freelist.pop(); if (magazine != NULL) { + inc_nmagazine(); return magazine; } @@ -180,4 +214,5 @@ ZMarkStackMagazine* ZMarkStackAllocator::alloc_magazine() { void ZMarkStackAllocator::free_magazine(ZMarkStackMagazine* magazine) { _freelist.push(magazine); + dec_nmagazine(); } diff --git a/src/hotspot/share/gc/z/zMarkStackAllocator.hpp b/src/hotspot/share/gc/z/zMarkStackAllocator.hpp index 55ce6e2e58186..123195c0c8b1b 100644 --- a/src/hotspot/share/gc/z/zMarkStackAllocator.hpp +++ b/src/hotspot/share/gc/z/zMarkStackAllocator.hpp @@ -52,8 +52,11 @@ class ZMarkStackAllocator { private: ZCACHE_ALIGNED ZMarkStackMagazineList _freelist; ZCACHE_ALIGNED ZMarkStackSpace _space; + ZCACHE_ALIGNED volatile int _nmagazine; void prime_freelist(); + void inc_nmagazine(); + void dec_nmagazine(); ZMarkStackMagazine* create_magazine_from_space(uintptr_t addr, size_t size); public: diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp index 4a49d775c8cb3..52641d60e3dcf 100644 --- a/src/hotspot/share/gc/z/z_globals.hpp +++ b/src/hotspot/share/gc/z/z_globals.hpp @@ -42,6 +42,9 @@ "Maximum number of bytes allocated for mark stacks") \ range(32*M, 1024*G) \ \ + product(double, ZStackModeChangeRatio, 0.25, \ + "Mark push mode is changed when usage is above the ratio") \ + \ product(double, ZCollectionInterval, 0, \ "Force GC at a fixed time interval (in seconds)") \ \