Skip to content

Commit

Permalink
8332841: GenShen: Pull shared members from control thread into common…
Browse files Browse the repository at this point in the history
… base class

Reviewed-by: ysr
  • Loading branch information
William Kemper committed May 24, 2024
1 parent 236432d commit ebc520e
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 141 deletions.
99 changes: 7 additions & 92 deletions src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
}
59 changes: 11 additions & 48 deletions src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -42,68 +43,30 @@ class ShenandoahControlThread: public ConcurrentGCThread {
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 changes: 112 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahController.cpp
Original file line number Diff line number Diff line change
@@ -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();
}

Loading

0 comments on commit ebc520e

Please sign in to comment.