< prev index next > src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp
Print this page
#include "gc/shenandoah/shenandoahConcurrentGC.hpp"
#include "gc/shenandoah/shenandoahControlThread.hpp"
#include "gc/shenandoah/shenandoahDegeneratedGC.hpp"
#include "gc/shenandoah/shenandoahFreeSet.hpp"
#include "gc/shenandoah/shenandoahFullGC.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
#include "gc/shenandoah/shenandoahPacer.inline.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "gc/shenandoah/heuristics/shenandoahHeuristics.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),
_requested_gc_cause(GCCause::_no_cause_specified),
! _degen_point(ShenandoahGC::_degenerated_outside_cycle),
- _allocs_seen(0) {
set_name("Shenandoah Control Thread");
- reset_gc_id();
create_and_start();
}
void ShenandoahControlThread::run_service() {
! ShenandoahHeap* heap = ShenandoahHeap::heap();
const GCMode default_mode = concurrent_normal;
const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc;
int sleep = ShenandoahControlIntervalMin;
#include "gc/shenandoah/shenandoahConcurrentGC.hpp"
#include "gc/shenandoah/shenandoahControlThread.hpp"
#include "gc/shenandoah/shenandoahDegeneratedGC.hpp"
#include "gc/shenandoah/shenandoahFreeSet.hpp"
#include "gc/shenandoah/shenandoahFullGC.hpp"
+ #include "gc/shenandoah/shenandoahGeneration.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
#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"
ShenandoahControlThread::ShenandoahControlThread() :
! ShenandoahController(),
_requested_gc_cause(GCCause::_no_cause_specified),
! _degen_point(ShenandoahGC::_degenerated_outside_cycle) {
set_name("Shenandoah Control Thread");
create_and_start();
}
void ShenandoahControlThread::run_service() {
! ShenandoahHeap* const heap = ShenandoahHeap::heap();
const GCMode default_mode = concurrent_normal;
const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc;
int sleep = ShenandoahControlIntervalMin;
const bool alloc_failure_pending = _alloc_failure_gc.is_set();
const bool is_gc_requested = _gc_requested.is_set();
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);
// Check if we have seen a new target for soft max heap size.
const bool soft_max_changed = heap->check_soft_max_changed();
// Choose which GC mode to run in. The block below should select a single mode.
const bool alloc_failure_pending = _alloc_failure_gc.is_set();
const bool is_gc_requested = _gc_requested.is_set();
const GCCause::Cause requested_gc_cause = _requested_gc_cause;
// This control loop iteration has seen this much allocation.
! 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();
// Choose which GC mode to run in. The block below should select a single mode.
} else {
heuristics->record_allocation_failure_gc();
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));
heuristics->record_requested_gc();
// GC is over, we are at idle now
if (ShenandoahPacing) {
heap->pacer()->setup_for_idle();
}
} else {
! // Allow allocators to know we have seen this much regions
if (ShenandoahPacing && (allocs_seen > 0)) {
heap->pacer()->report_alloc(allocs_seen);
}
}
// GC is over, we are at idle now
if (ShenandoahPacing) {
heap->pacer()->setup_for_idle();
}
} else {
! // Report to pacer that we have seen this many words allocated
if (ShenandoahPacing && (allocs_seen > 0)) {
heap->pacer()->report_alloc(allocs_seen);
}
}
//
ShenandoahHeap* heap = ShenandoahHeap::heap();
if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return;
GCIdMark gc_id_mark;
! ShenandoahGCSession session(cause);
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
! ShenandoahConcurrentGC gc;
if (gc.collect(cause)) {
// Cycle is complete
! heap->heuristics()->record_success_concurrent();
! heap->shenandoah_policy()->record_success_concurrent(gc.abbreviated());
} else {
assert(heap->cancelled_gc(), "Must have been cancelled");
check_cancellation_or_degen(gc.degen_point());
}
}
bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) {
ShenandoahHeap* heap = ShenandoahHeap::heap();
//
ShenandoahHeap* heap = ShenandoahHeap::heap();
if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return;
GCIdMark gc_id_mark;
! ShenandoahGCSession session(cause, heap->global_generation());
TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
! ShenandoahConcurrentGC gc(heap->global_generation(), false);
if (gc.collect(cause)) {
// Cycle is complete
! heap->global_generation()->heuristics()->record_success_concurrent(gc.abbreviated());
! heap->shenandoah_policy()->record_success_concurrent(false, gc.abbreviated());
+ heap->log_heap_status("At end of GC");
} else {
assert(heap->cancelled_gc(), "Must have been cancelled");
check_cancellation_or_degen(gc.degen_point());
+ heap->log_heap_status("At end of cancelled GC");
}
}
bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) {
ShenandoahHeap* heap = ShenandoahHeap::heap();
void ShenandoahControlThread::stop_service() {
// Nothing to do here.
}
void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {
GCIdMark gc_id_mark;
! ShenandoahGCSession session(cause);
ShenandoahFullGC gc;
gc.collect(cause);
}
void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point) {
assert (point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");
!
GCIdMark gc_id_mark;
! ShenandoahGCSession session(cause);
! ShenandoahDegenGC gc(point);
gc.collect(cause);
}
void ShenandoahControlThread::request_gc(GCCause::Cause cause) {
if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) {
void ShenandoahControlThread::stop_service() {
// Nothing to do here.
}
void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {
+ ShenandoahHeap* const heap = ShenandoahHeap::heap();
GCIdMark gc_id_mark;
! ShenandoahGCSession session(cause, heap->global_generation());
ShenandoahFullGC gc;
gc.collect(cause);
}
void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point) {
assert (point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");
! ShenandoahHeap* const heap = ShenandoahHeap::heap();
GCIdMark gc_id_mark;
! ShenandoahGCSession session(cause, heap->global_generation());
! ShenandoahDegenGC gc(point, heap->global_generation());
gc.collect(cause);
}
void ShenandoahControlThread::request_gc(GCCause::Cause cause) {
if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) {
}
current_gc_id = get_gc_id();
}
}
- 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();
- }
< prev index next >