8332841: GenShen: Pull shared members from control thread into common base class
Reviewed-by: ysr
This commit is contained in:
parent
236432dbdb
commit
ebc520e83f
src/hotspot/share/gc/shenandoah
@ -35,25 +35,21 @@
|
||||
#include "gc/shenandoah/shenandoahPacer.inline.hpp"
|
||||
#include "gc/shenandoah/shenandoahUtils.hpp"
|
||||
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
|
||||
#include "gc/shenandoah/mode/shenandoahMode.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/metaspaceUtils.hpp"
|
||||
#include "memory/metaspaceStats.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
|
||||
ShenandoahControlThread::ShenandoahControlThread() :
|
||||
ConcurrentGCThread(),
|
||||
_alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true),
|
||||
_gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true),
|
||||
ShenandoahController(),
|
||||
_requested_gc_cause(GCCause::_no_cause_specified),
|
||||
_degen_point(ShenandoahGC::_degenerated_outside_cycle),
|
||||
_allocs_seen(0) {
|
||||
_degen_point(ShenandoahGC::_degenerated_outside_cycle) {
|
||||
set_name("Shenandoah Control Thread");
|
||||
reset_gc_id();
|
||||
create_and_start();
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::run_service() {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
ShenandoahHeap* const heap = ShenandoahHeap::heap();
|
||||
|
||||
const GCMode default_mode = concurrent_normal;
|
||||
const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc;
|
||||
@ -77,7 +73,7 @@ void ShenandoahControlThread::run_service() {
|
||||
const GCCause::Cause requested_gc_cause = _requested_gc_cause;
|
||||
|
||||
// This control loop iteration has seen this much allocation.
|
||||
const size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed);
|
||||
const size_t allocs_seen = reset_allocs_seen();
|
||||
|
||||
// Check if we have seen a new target for soft max heap size.
|
||||
const bool soft_max_changed = heap->check_soft_max_changed();
|
||||
@ -106,7 +102,6 @@ void ShenandoahControlThread::run_service() {
|
||||
policy->record_alloc_failure_to_full();
|
||||
mode = stw_full;
|
||||
}
|
||||
|
||||
} else if (is_gc_requested) {
|
||||
cause = requested_gc_cause;
|
||||
log_info(gc)("Trigger: GC request (%s)", GCCause::to_string(cause));
|
||||
@ -239,7 +234,7 @@ void ShenandoahControlThread::run_service() {
|
||||
heap->pacer()->setup_for_idle();
|
||||
}
|
||||
} else {
|
||||
// Allow allocators to know we have seen this much regions
|
||||
// Report to pacer that we have seen this many words allocated
|
||||
if (ShenandoahPacing && (allocs_seen > 0)) {
|
||||
heap->pacer()->report_alloc(allocs_seen);
|
||||
}
|
||||
@ -407,88 +402,8 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) {
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
|
||||
assert(current()->is_Java_thread(), "expect Java thread here");
|
||||
|
||||
if (try_set_alloc_failure_gc()) {
|
||||
// Only report the first allocation failure
|
||||
log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s",
|
||||
req.type_string(),
|
||||
byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize));
|
||||
|
||||
// Now that alloc failure GC is scheduled, we can abort everything else
|
||||
heap->cancel_gc(GCCause::_allocation_failure);
|
||||
}
|
||||
|
||||
|
||||
if (block) {
|
||||
MonitorLocker ml(&_alloc_failure_waiters_lock);
|
||||
while (is_alloc_failure_gc()) {
|
||||
ml.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::handle_alloc_failure_evac(size_t words) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
|
||||
if (try_set_alloc_failure_gc()) {
|
||||
// Only report the first allocation failure
|
||||
log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation",
|
||||
byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize));
|
||||
}
|
||||
|
||||
// Forcefully report allocation failure
|
||||
heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac);
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::notify_alloc_failure_waiters() {
|
||||
_alloc_failure_gc.unset();
|
||||
MonitorLocker ml(&_alloc_failure_waiters_lock);
|
||||
ml.notify_all();
|
||||
}
|
||||
|
||||
bool ShenandoahControlThread::try_set_alloc_failure_gc() {
|
||||
return _alloc_failure_gc.try_set();
|
||||
}
|
||||
|
||||
bool ShenandoahControlThread::is_alloc_failure_gc() {
|
||||
return _alloc_failure_gc.is_set();
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::notify_gc_waiters() {
|
||||
_gc_requested.unset();
|
||||
MonitorLocker ml(&_gc_waiters_lock);
|
||||
ml.notify_all();
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::pacing_notify_alloc(size_t words) {
|
||||
assert(ShenandoahPacing, "should only call when pacing is enabled");
|
||||
Atomic::add(&_allocs_seen, words, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::reset_gc_id() {
|
||||
Atomic::store(&_gc_id, (size_t)0);
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::update_gc_id() {
|
||||
Atomic::inc(&_gc_id);
|
||||
}
|
||||
|
||||
size_t ShenandoahControlThread::get_gc_id() {
|
||||
return Atomic::load(&_gc_id);
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::start() {
|
||||
create_and_start();
|
||||
}
|
||||
|
||||
void ShenandoahControlThread::prepare_for_graceful_shutdown() {
|
||||
_graceful_shutdown.set();
|
||||
}
|
||||
|
||||
bool ShenandoahControlThread::in_graceful_shutdown() {
|
||||
return _graceful_shutdown.is_set();
|
||||
}
|
||||
|
@ -28,10 +28,11 @@
|
||||
#include "gc/shared/gcCause.hpp"
|
||||
#include "gc/shared/concurrentGCThread.hpp"
|
||||
#include "gc/shenandoah/shenandoahGC.hpp"
|
||||
#include "gc/shenandoah/shenandoahController.hpp"
|
||||
#include "gc/shenandoah/shenandoahPadding.hpp"
|
||||
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
|
||||
|
||||
class ShenandoahControlThread: public ConcurrentGCThread {
|
||||
class ShenandoahControlThread: public ShenandoahController {
|
||||
friend class VMStructs;
|
||||
|
||||
private:
|
||||
@ -42,68 +43,30 @@ private:
|
||||
stw_full
|
||||
} GCMode;
|
||||
|
||||
// While we could have a single lock for these, it may risk unblocking
|
||||
// GC waiters when alloc failure GC cycle finishes. We want instead
|
||||
// to make complete explicit cycle for for demanding customers.
|
||||
Monitor _alloc_failure_waiters_lock;
|
||||
Monitor _gc_waiters_lock;
|
||||
|
||||
public:
|
||||
void run_service();
|
||||
void stop_service();
|
||||
|
||||
private:
|
||||
ShenandoahSharedFlag _gc_requested;
|
||||
ShenandoahSharedFlag _alloc_failure_gc;
|
||||
ShenandoahSharedFlag _graceful_shutdown;
|
||||
GCCause::Cause _requested_gc_cause;
|
||||
ShenandoahGC::ShenandoahDegenPoint _degen_point;
|
||||
|
||||
shenandoah_padding(0);
|
||||
volatile size_t _allocs_seen;
|
||||
shenandoah_padding(1);
|
||||
volatile size_t _gc_id;
|
||||
shenandoah_padding(2);
|
||||
public:
|
||||
ShenandoahControlThread();
|
||||
|
||||
void run_service() override;
|
||||
void stop_service() override;
|
||||
|
||||
void request_gc(GCCause::Cause cause) override;
|
||||
|
||||
private:
|
||||
|
||||
bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point);
|
||||
void service_concurrent_normal_cycle(GCCause::Cause cause);
|
||||
void service_stw_full_cycle(GCCause::Cause cause);
|
||||
void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point);
|
||||
|
||||
bool try_set_alloc_failure_gc();
|
||||
void notify_alloc_failure_waiters();
|
||||
bool is_alloc_failure_gc();
|
||||
|
||||
void reset_gc_id();
|
||||
void update_gc_id();
|
||||
size_t get_gc_id();
|
||||
|
||||
void notify_gc_waiters();
|
||||
|
||||
// Handle GC request.
|
||||
// Blocks until GC is over.
|
||||
void handle_requested_gc(GCCause::Cause cause);
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
ShenandoahControlThread();
|
||||
|
||||
// Handle allocation failure from a mutator allocation.
|
||||
// Optionally blocks while collector is handling the failure. If the GC
|
||||
// threshold has been exceeded, the mutator allocation will not block so
|
||||
// that the out of memory error can be raised promptly.
|
||||
void handle_alloc_failure(ShenandoahAllocRequest& req, bool block = true);
|
||||
|
||||
// Handle allocation failure from evacuation path.
|
||||
void handle_alloc_failure_evac(size_t words);
|
||||
|
||||
void request_gc(GCCause::Cause cause);
|
||||
|
||||
void pacing_notify_alloc(size_t words);
|
||||
|
||||
void start();
|
||||
void prepare_for_graceful_shutdown();
|
||||
bool in_graceful_shutdown();
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP
|
||||
|
112
src/hotspot/share/gc/shenandoah/shenandoahController.cpp
Normal file
112
src/hotspot/share/gc/shenandoah/shenandoahController.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. 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/shared/gc_globals.hpp"
|
||||
#include "gc/shenandoah/shenandoahController.hpp"
|
||||
#include "gc/shenandoah/shenandoahHeap.hpp"
|
||||
#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
|
||||
|
||||
void ShenandoahController::pacing_notify_alloc(size_t words) {
|
||||
assert(ShenandoahPacing, "should only call when pacing is enabled");
|
||||
Atomic::add(&_allocs_seen, words, memory_order_relaxed);
|
||||
}
|
||||
|
||||
size_t ShenandoahController::reset_allocs_seen() {
|
||||
return Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void ShenandoahController::prepare_for_graceful_shutdown() {
|
||||
_graceful_shutdown.set();
|
||||
}
|
||||
|
||||
bool ShenandoahController::in_graceful_shutdown() {
|
||||
return _graceful_shutdown.is_set();
|
||||
}
|
||||
|
||||
void ShenandoahController::update_gc_id() {
|
||||
Atomic::inc(&_gc_id);
|
||||
}
|
||||
|
||||
size_t ShenandoahController::get_gc_id() {
|
||||
return Atomic::load(&_gc_id);
|
||||
}
|
||||
|
||||
void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
|
||||
assert(current()->is_Java_thread(), "expect Java thread here");
|
||||
bool is_humongous = req.size() > ShenandoahHeapRegion::humongous_threshold_words();
|
||||
|
||||
if (try_set_alloc_failure_gc(is_humongous)) {
|
||||
// Only report the first allocation failure
|
||||
log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s",
|
||||
req.type_string(),
|
||||
byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize));
|
||||
|
||||
// Now that alloc failure GC is scheduled, we can abort everything else
|
||||
heap->cancel_gc(GCCause::_allocation_failure);
|
||||
}
|
||||
|
||||
|
||||
if (block) {
|
||||
MonitorLocker ml(&_alloc_failure_waiters_lock);
|
||||
while (is_alloc_failure_gc()) {
|
||||
ml.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahController::handle_alloc_failure_evac(size_t words) {
|
||||
ShenandoahHeap* heap = ShenandoahHeap::heap();
|
||||
bool is_humongous = (words > ShenandoahHeapRegion::region_size_words());
|
||||
|
||||
if (try_set_alloc_failure_gc(is_humongous)) {
|
||||
// Only report the first allocation failure
|
||||
log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation",
|
||||
byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize));
|
||||
}
|
||||
|
||||
// Forcefully report allocation failure
|
||||
heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac);
|
||||
}
|
||||
|
||||
void ShenandoahController::notify_alloc_failure_waiters() {
|
||||
_alloc_failure_gc.unset();
|
||||
_humongous_alloc_failure_gc.unset();
|
||||
MonitorLocker ml(&_alloc_failure_waiters_lock);
|
||||
ml.notify_all();
|
||||
}
|
||||
|
||||
bool ShenandoahController::try_set_alloc_failure_gc(bool is_humongous) {
|
||||
if (is_humongous) {
|
||||
_humongous_alloc_failure_gc.try_set();
|
||||
}
|
||||
return _alloc_failure_gc.try_set();
|
||||
}
|
||||
|
||||
bool ShenandoahController::is_alloc_failure_gc() {
|
||||
return _alloc_failure_gc.is_set();
|
||||
}
|
||||
|
105
src/hotspot/share/gc/shenandoah/shenandoahController.hpp
Normal file
105
src/hotspot/share/gc/shenandoah/shenandoahController.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. 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 LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP
|
||||
#define LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP
|
||||
|
||||
#include "gc/shared/gcCause.hpp"
|
||||
#include "gc/shared/concurrentGCThread.hpp"
|
||||
#include "gc/shenandoah/shenandoahAllocRequest.hpp"
|
||||
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
|
||||
|
||||
/**
|
||||
* This interface exposes methods necessary for the heap to interact
|
||||
* with the threads responsible for driving the collection cycle.
|
||||
*/
|
||||
class ShenandoahController: public ConcurrentGCThread {
|
||||
private:
|
||||
ShenandoahSharedFlag _graceful_shutdown;
|
||||
|
||||
shenandoah_padding(0);
|
||||
volatile size_t _allocs_seen;
|
||||
shenandoah_padding(1);
|
||||
volatile size_t _gc_id;
|
||||
shenandoah_padding(2);
|
||||
|
||||
protected:
|
||||
ShenandoahSharedFlag _alloc_failure_gc;
|
||||
ShenandoahSharedFlag _humongous_alloc_failure_gc;
|
||||
|
||||
// While we could have a single lock for these, it may risk unblocking
|
||||
// GC waiters when alloc failure GC cycle finishes. We want instead
|
||||
// to make complete explicit cycle for demanding customers.
|
||||
Monitor _alloc_failure_waiters_lock;
|
||||
Monitor _gc_waiters_lock;
|
||||
|
||||
public:
|
||||
ShenandoahController():
|
||||
ConcurrentGCThread(),
|
||||
_allocs_seen(0),
|
||||
_gc_id(0),
|
||||
_alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true),
|
||||
_gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true)
|
||||
{ }
|
||||
|
||||
// Request a collection cycle. This handles "explicit" gc requests
|
||||
// like System.gc and "implicit" gc requests, like metaspace oom.
|
||||
virtual void request_gc(GCCause::Cause cause) = 0;
|
||||
|
||||
// This cancels the collection cycle and has an option to block
|
||||
// until another cycle runs and clears the alloc failure gc flag.
|
||||
void handle_alloc_failure(ShenandoahAllocRequest& req, bool block);
|
||||
|
||||
// Invoked for allocation failures during evacuation. This cancels
|
||||
// the collection cycle without blocking.
|
||||
void handle_alloc_failure_evac(size_t words);
|
||||
|
||||
// Return true if setting the flag which indicates allocation failure succeeds.
|
||||
bool try_set_alloc_failure_gc(bool is_humongous);
|
||||
|
||||
// Notify threads waiting for GC to complete.
|
||||
void notify_alloc_failure_waiters();
|
||||
|
||||
// True if allocation failure flag has been set.
|
||||
bool is_alloc_failure_gc();
|
||||
|
||||
// This is called for every allocation. The control thread accumulates
|
||||
// this value when idle. During the gc cycle, the control resets it
|
||||
// and reports it to the pacer.
|
||||
void pacing_notify_alloc(size_t words);
|
||||
size_t reset_allocs_seen();
|
||||
|
||||
// These essentially allows to cancel a collection cycle for the
|
||||
// purpose of shutting down the JVM, without trying to start a degenerated
|
||||
// cycle.
|
||||
void prepare_for_graceful_shutdown();
|
||||
bool in_graceful_shutdown();
|
||||
|
||||
|
||||
// Returns the internal gc count used by the control thread. Probably
|
||||
// doesn't need to be exposed.
|
||||
size_t get_gc_id();
|
||||
void update_gc_id();
|
||||
};
|
||||
#endif //LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP
|
@ -955,7 +955,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) {
|
||||
size_t original_count = shenandoah_policy()->full_gc_count();
|
||||
while (result == nullptr
|
||||
&& (get_gc_no_progress_count() == 0 || original_count == shenandoah_policy()->full_gc_count())) {
|
||||
control_thread()->handle_alloc_failure(req);
|
||||
control_thread()->handle_alloc_failure(req, true);
|
||||
result = allocate_memory_under_lock(req, in_new_region);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user