< prev index next > src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp
Print this page
/*
* Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved.
+ * 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.
*
*/
#include "precompiled.hpp"
#include "gc/shared/gcCause.hpp"
- #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
- #include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
#include "logging/log.hpp"
#include "logging/logTag.hpp"
#include "runtime/globals_extension.hpp"
int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) {
! if (a._garbage > b._garbage)
return -1;
! else if (a._garbage < b._garbage)
return 1;
! else return 0;
}
! ShenandoahHeuristics::ShenandoahHeuristics() :
_region_data(nullptr),
! _degenerated_cycles_in_a_row(0),
- _successful_cycles_in_a_row(0),
_cycle_start(os::elapsedTime()),
_last_cycle_end(0),
_gc_times_learned(0),
_gc_time_penalties(0),
! _gc_time_history(new TruncatedSeq(10, ShenandoahAdaptiveDecayFactor)),
_metaspace_oom()
{
size_t num_regions = ShenandoahHeap::heap()->num_regions();
assert(num_regions > 0, "Sanity");
_region_data = NEW_C_HEAP_ARRAY(RegionData, num_regions, mtGC);
}
ShenandoahHeuristics::~ShenandoahHeuristics() {
FREE_C_HEAP_ARRAY(RegionGarbage, _region_data);
}
void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) {
! assert(collection_set->count() == 0, "Must be empty");
ShenandoahHeap* heap = ShenandoahHeap::heap();
// Check all pinned regions have updated status before choosing the collection set.
heap->assert_pinned_region_status();
*
*/
#include "precompiled.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
#include "logging/log.hpp"
#include "logging/logTag.hpp"
#include "runtime/globals_extension.hpp"
+ #include "utilities/quickSort.hpp"
+ // sort by decreasing garbage (so most garbage comes first)
int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) {
! if (a.get_garbage() > b.get_garbage()) {
return -1;
! } else if (a.get_garbage() < b.get_garbage()) {
return 1;
! } else {
+ return 0;
+ }
}
! ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) :
+ _space_info(space_info),
_region_data(nullptr),
! _guaranteed_gc_interval(0),
_cycle_start(os::elapsedTime()),
_last_cycle_end(0),
_gc_times_learned(0),
_gc_time_penalties(0),
! _gc_cycle_time_history(new TruncatedSeq(Moving_Average_Samples, ShenandoahAdaptiveDecayFactor)),
_metaspace_oom()
{
size_t num_regions = ShenandoahHeap::heap()->num_regions();
assert(num_regions > 0, "Sanity");
_region_data = NEW_C_HEAP_ARRAY(RegionData, num_regions, mtGC);
+ for (size_t i = 0; i < num_regions; i++) {
+ _region_data[i].clear();
+ }
}
ShenandoahHeuristics::~ShenandoahHeuristics() {
FREE_C_HEAP_ARRAY(RegionGarbage, _region_data);
}
void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) {
! assert(collection_set->is_empty(), "Must be empty");
ShenandoahHeap* heap = ShenandoahHeap::heap();
// Check all pinned regions have updated status before choosing the collection set.
heap->assert_pinned_region_status();
immediate_regions++;
immediate_garbage += garbage;
region->make_trash_immediate();
} else {
// This is our candidate for later consideration.
! candidates[cand_idx]._region = region;
- candidates[cand_idx]._garbage = garbage;
cand_idx++;
}
} else if (region->is_humongous_start()) {
// Reclaim humongous regions here, and count them as the immediate garbage
#ifdef ASSERT
immediate_regions++;
immediate_garbage += garbage;
region->make_trash_immediate();
} else {
// This is our candidate for later consideration.
! candidates[cand_idx].set_region_and_garbage(region, garbage);
cand_idx++;
}
} else if (region->is_humongous_start()) {
// Reclaim humongous regions here, and count them as the immediate garbage
#ifdef ASSERT
if (immediate_percent <= ShenandoahImmediateThreshold) {
choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free);
}
size_t cset_percent = (total_garbage == 0) ? 0 : (collection_set->garbage() * 100 / total_garbage);
-
size_t collectable_garbage = collection_set->garbage() + immediate_garbage;
size_t collectable_garbage_percent = (total_garbage == 0) ? 0 : (collectable_garbage * 100 / total_garbage);
log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
! "Immediate: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
! "CSet: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%)",
byte_size_in_proper_unit(collectable_garbage),
proper_unit_for_byte_size(collectable_garbage),
collectable_garbage_percent,
byte_size_in_proper_unit(immediate_garbage),
proper_unit_for_byte_size(immediate_garbage),
immediate_percent,
byte_size_in_proper_unit(collection_set->garbage()),
proper_unit_for_byte_size(collection_set->garbage()),
! cset_percent);
}
void ShenandoahHeuristics::record_cycle_start() {
_cycle_start = os::elapsedTime();
}
if (immediate_percent <= ShenandoahImmediateThreshold) {
choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free);
}
size_t cset_percent = (total_garbage == 0) ? 0 : (collection_set->garbage() * 100 / total_garbage);
size_t collectable_garbage = collection_set->garbage() + immediate_garbage;
size_t collectable_garbage_percent = (total_garbage == 0) ? 0 : (collectable_garbage * 100 / total_garbage);
log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
! "Immediate: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), " SIZE_FORMAT " regions, "
! "CSet: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), " SIZE_FORMAT " regions",
byte_size_in_proper_unit(collectable_garbage),
proper_unit_for_byte_size(collectable_garbage),
collectable_garbage_percent,
byte_size_in_proper_unit(immediate_garbage),
proper_unit_for_byte_size(immediate_garbage),
immediate_percent,
+ immediate_regions,
byte_size_in_proper_unit(collection_set->garbage()),
proper_unit_for_byte_size(collection_set->garbage()),
! cset_percent,
+ collection_set->count());
}
void ShenandoahHeuristics::record_cycle_start() {
_cycle_start = os::elapsedTime();
}
bool ShenandoahHeuristics::should_start_gc() {
// Perform GC to cleanup metaspace
if (has_metaspace_oom()) {
// Some of vmTestbase/metaspace tests depend on following line to count GC cycles
! log_info(gc)("Trigger: %s", GCCause::to_string(GCCause::_metadata_GC_threshold));
return true;
}
! if (ShenandoahGuaranteedGCInterval > 0) {
double last_time_ms = (os::elapsedTime() - _last_cycle_end) * 1000;
! if (last_time_ms > ShenandoahGuaranteedGCInterval) {
! log_info(gc)("Trigger: Time since last GC (%.0f ms) is larger than guaranteed interval (" UINTX_FORMAT " ms)",
! last_time_ms, ShenandoahGuaranteedGCInterval);
return true;
}
}
return false;
}
bool ShenandoahHeuristics::should_degenerate_cycle() {
! return _degenerated_cycles_in_a_row <= ShenandoahFullGCThreshold;
}
void ShenandoahHeuristics::adjust_penalty(intx step) {
assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
! "In range before adjustment: " INTX_FORMAT, _gc_time_penalties);
intx new_val = _gc_time_penalties + step;
if (new_val < 0) {
new_val = 0;
}
bool ShenandoahHeuristics::should_start_gc() {
// Perform GC to cleanup metaspace
if (has_metaspace_oom()) {
// Some of vmTestbase/metaspace tests depend on following line to count GC cycles
! log_trigger("%s", GCCause::to_string(GCCause::_metadata_GC_threshold));
return true;
}
! if (_guaranteed_gc_interval > 0) {
double last_time_ms = (os::elapsedTime() - _last_cycle_end) * 1000;
! if (last_time_ms > _guaranteed_gc_interval) {
! log_trigger("Time since last GC (%.0f ms) is larger than guaranteed interval (" UINTX_FORMAT " ms)",
! last_time_ms, _guaranteed_gc_interval);
return true;
}
}
return false;
}
bool ShenandoahHeuristics::should_degenerate_cycle() {
! return ShenandoahHeap::heap()->shenandoah_policy()->consecutive_degenerated_gc_count() <= ShenandoahFullGCThreshold;
}
void ShenandoahHeuristics::adjust_penalty(intx step) {
assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
! "In range before adjustment: " INTX_FORMAT, _gc_time_penalties);
intx new_val = _gc_time_penalties + step;
if (new_val < 0) {
new_val = 0;
}
new_val = 100;
}
_gc_time_penalties = new_val;
assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
! "In range after adjustment: " INTX_FORMAT, _gc_time_penalties);
}
! void ShenandoahHeuristics::record_success_concurrent() {
! _degenerated_cycles_in_a_row = 0;
! _successful_cycles_in_a_row++;
! _gc_time_history->add(time_since_last_gc());
_gc_times_learned++;
adjust_penalty(Concurrent_Adjust);
}
void ShenandoahHeuristics::record_success_degenerated() {
- _degenerated_cycles_in_a_row++;
- _successful_cycles_in_a_row = 0;
-
adjust_penalty(Degenerated_Penalty);
}
void ShenandoahHeuristics::record_success_full() {
- _degenerated_cycles_in_a_row = 0;
- _successful_cycles_in_a_row++;
-
adjust_penalty(Full_Penalty);
}
void ShenandoahHeuristics::record_allocation_failure_gc() {
// Do nothing.
new_val = 100;
}
_gc_time_penalties = new_val;
assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
! "In range after adjustment: " INTX_FORMAT, _gc_time_penalties);
}
! void ShenandoahHeuristics::log_trigger(const char* fmt, ...) {
! LogTarget(Info, gc) lt;
! if (lt.is_enabled()) {
+ ResourceMark rm;
+ LogStream ls(lt);
+ ls.print_raw("Trigger", 7);
+ if (ShenandoahHeap::heap()->mode()->is_generational()) {
+ ls.print(" (%s)", _space_info->name());
+ }
+ ls.print_raw(": ", 2);
+ va_list va;
+ va_start(va, fmt);
+ ls.vprint(fmt, va);
+ va_end(va);
+ ls.cr();
+ }
+ }
! void ShenandoahHeuristics::record_success_concurrent() {
+ _gc_cycle_time_history->add(elapsed_cycle_time());
_gc_times_learned++;
adjust_penalty(Concurrent_Adjust);
}
void ShenandoahHeuristics::record_success_degenerated() {
adjust_penalty(Degenerated_Penalty);
}
void ShenandoahHeuristics::record_success_full() {
adjust_penalty(Full_Penalty);
}
void ShenandoahHeuristics::record_allocation_failure_gc() {
// Do nothing.
// which forces us to re-learn the GC timings and allocation rates.
_gc_times_learned = 0;
}
bool ShenandoahHeuristics::can_unload_classes() {
! if (!ClassUnloading) return false;
- return true;
}
bool ShenandoahHeuristics::should_unload_classes() {
if (!can_unload_classes()) return false;
if (has_metaspace_oom()) return true;
// which forces us to re-learn the GC timings and allocation rates.
_gc_times_learned = 0;
}
bool ShenandoahHeuristics::can_unload_classes() {
! return ClassUnloading;
}
bool ShenandoahHeuristics::should_unload_classes() {
if (!can_unload_classes()) return false;
if (has_metaspace_oom()) return true;
void ShenandoahHeuristics::initialize() {
// Nothing to do by default.
}
! double ShenandoahHeuristics::time_since_last_gc() const {
return os::elapsedTime() - _cycle_start;
}
void ShenandoahHeuristics::initialize() {
// Nothing to do by default.
}
! double ShenandoahHeuristics::elapsed_cycle_time() const {
return os::elapsedTime() - _cycle_start;
}
< prev index next >