8248650: [BACKOUT] Backout JDK-8244603 because it generates too much noise in CI
Reviewed-by: kbarrett
This commit is contained in:
parent
51937e18f8
commit
dc63bf261b
@ -224,11 +224,7 @@ void G1Analytics::report_rs_length(double rs_length) {
|
||||
}
|
||||
|
||||
double G1Analytics::predict_alloc_rate_ms() const {
|
||||
if (enough_samples_available(_alloc_rate_ms_seq)) {
|
||||
return predict_zero_bounded(_alloc_rate_ms_seq);
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
return predict_zero_bounded(_alloc_rate_ms_seq);
|
||||
}
|
||||
|
||||
double G1Analytics::predict_concurrent_refine_rate_ms() const {
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "gc/shared/gcPolicyCounters.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
@ -62,8 +61,8 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) :
|
||||
_policy_counters(new GCPolicyCounters("GarbageFirst", 1, 2)),
|
||||
_full_collection_start_sec(0.0),
|
||||
_collection_pause_end_millis(os::javaTimeNanos() / NANOSECS_PER_MILLISEC),
|
||||
_young_list_desired_length(0),
|
||||
_young_list_target_length(0),
|
||||
_young_list_fixed_length(0),
|
||||
_young_list_max_length(0),
|
||||
_eden_surv_rate_group(new G1SurvRateGroup()),
|
||||
_survivor_surv_rate_group(new G1SurvRateGroup()),
|
||||
@ -108,11 +107,14 @@ void G1Policy::init(G1CollectedHeap* g1h, G1CollectionSet* collection_set) {
|
||||
|
||||
assert(Heap_lock->owned_by_self(), "Locking discipline.");
|
||||
|
||||
if (!use_adaptive_young_list_length()) {
|
||||
_young_list_fixed_length = _young_gen_sizer->min_desired_young_length();
|
||||
}
|
||||
_young_gen_sizer->adjust_max_new_size(_g1h->max_expandable_regions());
|
||||
|
||||
_free_regions_at_end_of_collection = _g1h->num_free_regions();
|
||||
|
||||
update_young_length_bounds();
|
||||
update_young_list_max_and_target_length();
|
||||
// We may immediately start allocating regions and placing them on the
|
||||
// collection set list. Initialize the per-collection set info
|
||||
_collection_set->start_incremental_building();
|
||||
@ -187,254 +189,158 @@ void G1Policy::record_new_heap_size(uint new_number_of_regions) {
|
||||
_ihop_control->update_target_occupancy(new_number_of_regions * HeapRegion::GrainBytes);
|
||||
}
|
||||
|
||||
uint G1Policy::calculate_desired_eden_length_by_mmu() const {
|
||||
// One could argue that any useful eden length to keep any MMU would be 1, but
|
||||
// in theory this is possible. Other constraints enforce a minimum eden of 1
|
||||
// anyway.
|
||||
uint G1Policy::calculate_young_list_desired_min_length(uint base_min_length) const {
|
||||
uint desired_min_length = 0;
|
||||
if (use_adaptive_young_list_length()) {
|
||||
double now_sec = os::elapsedTime();
|
||||
double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0;
|
||||
double alloc_rate_ms = _analytics->predict_alloc_rate_ms();
|
||||
desired_min_length = (uint) ceil(alloc_rate_ms * when_ms);
|
||||
if (_analytics->num_alloc_rate_ms() > 3) {
|
||||
double now_sec = os::elapsedTime();
|
||||
double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0;
|
||||
double alloc_rate_ms = _analytics->predict_alloc_rate_ms();
|
||||
desired_min_length = (uint) ceil(alloc_rate_ms * when_ms);
|
||||
} else {
|
||||
// otherwise we don't have enough info to make the prediction
|
||||
}
|
||||
}
|
||||
return desired_min_length;
|
||||
desired_min_length += base_min_length;
|
||||
// make sure we don't go below any user-defined minimum bound
|
||||
return MAX2(_young_gen_sizer->min_desired_young_length(), desired_min_length);
|
||||
}
|
||||
|
||||
void G1Policy::update_young_length_bounds() {
|
||||
update_young_length_bounds(_analytics->predict_rs_length());
|
||||
uint G1Policy::calculate_young_list_desired_max_length() const {
|
||||
// Here, we might want to also take into account any additional
|
||||
// constraints (i.e., user-defined minimum bound). Currently, we
|
||||
// effectively don't set this bound.
|
||||
return _young_gen_sizer->max_desired_young_length();
|
||||
}
|
||||
|
||||
void G1Policy::update_young_length_bounds(size_t rs_length) {
|
||||
_young_list_desired_length = calculate_young_desired_length(rs_length);
|
||||
_young_list_target_length = calculate_young_target_length(_young_list_desired_length);
|
||||
_young_list_max_length = calculate_young_max_length(_young_list_target_length);
|
||||
|
||||
log_debug(gc,ergo,heap)("Young list lengths: desired: %u, target: %u, max: %u",
|
||||
_young_list_desired_length,
|
||||
_young_list_target_length,
|
||||
_young_list_max_length);
|
||||
uint G1Policy::update_young_list_max_and_target_length() {
|
||||
return update_young_list_max_and_target_length(_analytics->predict_rs_length());
|
||||
}
|
||||
|
||||
// Calculates desired young gen length. It is calculated from:
|
||||
//
|
||||
// - sizer min/max bounds on young gen
|
||||
// - pause time goal for whole young gen evacuation
|
||||
// - MMU goal influencing eden to make GCs spaced apart.
|
||||
// - a minimum one eden region length.
|
||||
//
|
||||
// We may enter with already allocated eden and survivor regions, that may be
|
||||
// higher than the maximum, or the above goals may result in a desired value
|
||||
// smaller than are already allocated.
|
||||
// The main reason is revising young length, with our without the GCLocker being
|
||||
// active.
|
||||
//
|
||||
uint G1Policy::calculate_young_desired_length(size_t rs_length) const {
|
||||
uint min_young_length_by_sizer = _young_gen_sizer->min_desired_young_length();
|
||||
uint max_young_length_by_sizer = _young_gen_sizer->max_desired_young_length();
|
||||
uint G1Policy::update_young_list_max_and_target_length(size_t rs_length) {
|
||||
uint unbounded_target_length = update_young_list_target_length(rs_length);
|
||||
update_max_gc_locker_expansion();
|
||||
return unbounded_target_length;
|
||||
}
|
||||
|
||||
assert(min_young_length_by_sizer >= 1, "invariant");
|
||||
assert(max_young_length_by_sizer >= min_young_length_by_sizer, "invariant");
|
||||
uint G1Policy::update_young_list_target_length(size_t rs_length) {
|
||||
YoungTargetLengths young_lengths = young_list_target_lengths(rs_length);
|
||||
_young_list_target_length = young_lengths.first;
|
||||
|
||||
// Absolute minimum eden length.
|
||||
// Enforcing a minimum eden length helps at startup when the predictors are not
|
||||
// yet trained on the application to avoid unnecessary (but very short) full gcs
|
||||
// on very small (initial) heaps.
|
||||
uint const MinDesiredEdenLength = 1;
|
||||
return young_lengths.second;
|
||||
}
|
||||
|
||||
G1Policy::YoungTargetLengths G1Policy::young_list_target_lengths(size_t rs_length) const {
|
||||
YoungTargetLengths result;
|
||||
|
||||
// Calculate the absolute and desired min bounds first.
|
||||
|
||||
// This is how many survivor regions we already have.
|
||||
const uint survivor_length = _g1h->survivor_regions_count();
|
||||
// Size of the already allocated young gen.
|
||||
const uint allocated_young_length = _g1h->young_regions_count();
|
||||
// This is the absolute minimum young length that we can return. Ensure that we
|
||||
// don't go below any user-defined minimum bound; but we might have already
|
||||
// allocated more than that for reasons. In this case, use that.
|
||||
uint absolute_min_young_length = MAX2(allocated_young_length, min_young_length_by_sizer);
|
||||
// Calculate the absolute max bounds. After evac failure or when revising the
|
||||
// young length we might have exceeded absolute min length or absolute_max_length,
|
||||
// so adjust the result accordingly.
|
||||
uint absolute_max_young_length = MAX2(max_young_length_by_sizer, absolute_min_young_length);
|
||||
// This is how many young regions we already have (currently: the survivors).
|
||||
const uint base_min_length = _g1h->survivor_regions_count();
|
||||
uint desired_min_length = calculate_young_list_desired_min_length(base_min_length);
|
||||
// This is the absolute minimum young length. Ensure that we
|
||||
// will at least have one eden region available for allocation.
|
||||
uint absolute_min_length = base_min_length + MAX2(_g1h->eden_regions_count(), (uint)1);
|
||||
// If we shrank the young list target it should not shrink below the current size.
|
||||
desired_min_length = MAX2(desired_min_length, absolute_min_length);
|
||||
// Calculate the absolute and desired max bounds.
|
||||
|
||||
uint desired_eden_length_by_mmu = 0;
|
||||
uint desired_eden_length_by_pause = 0;
|
||||
uint desired_eden_length_before_mixed = 0;
|
||||
uint desired_max_length = calculate_young_list_desired_max_length();
|
||||
|
||||
uint desired_young_length = 0;
|
||||
uint young_list_target_length = 0;
|
||||
if (use_adaptive_young_list_length()) {
|
||||
desired_eden_length_by_mmu = calculate_desired_eden_length_by_mmu();
|
||||
|
||||
const size_t pending_cards = _analytics->predict_pending_cards();
|
||||
double survivor_base_time_ms = predict_base_elapsed_time_ms(pending_cards, rs_length);
|
||||
|
||||
if (!next_gc_should_be_mixed(NULL, NULL)) {
|
||||
desired_eden_length_by_pause =
|
||||
calculate_desired_eden_length_by_pause(survivor_base_time_ms,
|
||||
absolute_min_young_length - survivor_length,
|
||||
absolute_max_young_length - survivor_length);
|
||||
if (collector_state()->in_young_only_phase()) {
|
||||
young_list_target_length =
|
||||
calculate_young_list_target_length(rs_length,
|
||||
base_min_length,
|
||||
desired_min_length,
|
||||
desired_max_length);
|
||||
} else {
|
||||
desired_eden_length_before_mixed =
|
||||
calculate_desired_eden_length_before_mixed(survivor_base_time_ms,
|
||||
absolute_min_young_length - survivor_length,
|
||||
absolute_max_young_length - survivor_length);
|
||||
// Don't calculate anything and let the code below bound it to
|
||||
// the desired_min_length, i.e., do the next GC as soon as
|
||||
// possible to maximize how many old regions we can add to it.
|
||||
}
|
||||
// Above either sets desired_eden_length_by_pause or desired_eden_length_before_mixed,
|
||||
// the other is zero. Use the one that has been set below.
|
||||
uint desired_eden_length = MAX2(desired_eden_length_by_pause,
|
||||
desired_eden_length_before_mixed);
|
||||
|
||||
// Finally incorporate MMU concerns; assume that it overrides the pause time
|
||||
// goal, as the default value has been chosen to effectively disable it.
|
||||
// Also request at least one eden region, see above for reasons.
|
||||
desired_eden_length = MAX3(desired_eden_length,
|
||||
desired_eden_length_by_mmu,
|
||||
MinDesiredEdenLength);
|
||||
|
||||
desired_young_length = desired_eden_length + survivor_length;
|
||||
} else {
|
||||
// The user asked for a fixed young gen so we'll fix the young gen
|
||||
// whether the next GC is young or mixed.
|
||||
desired_young_length = min_young_length_by_sizer;
|
||||
}
|
||||
// Clamp to absolute min/max after we determined desired lengths.
|
||||
desired_young_length = clamp(desired_young_length, absolute_min_young_length, absolute_max_young_length);
|
||||
|
||||
log_trace(gc, ergo, heap)("Young desired length %u "
|
||||
"survivor length %u "
|
||||
"allocated young length %u "
|
||||
"absolute min young length %u "
|
||||
"absolute max young length %u "
|
||||
"desired eden length by mmu %u "
|
||||
"desired eden length by pause %u "
|
||||
"desired eden length before mixed %u"
|
||||
"desired eden length by default %u",
|
||||
desired_young_length, survivor_length,
|
||||
allocated_young_length, absolute_min_young_length,
|
||||
absolute_max_young_length, desired_eden_length_by_mmu,
|
||||
desired_eden_length_by_pause,
|
||||
desired_eden_length_before_mixed,
|
||||
MinDesiredEdenLength);
|
||||
|
||||
assert(desired_young_length >= allocated_young_length, "must be");
|
||||
return desired_young_length;
|
||||
}
|
||||
|
||||
// Limit the desired (wished) young length by current free regions. If the request
|
||||
// can be satisfied without using up reserve regions, do so, otherwise eat into
|
||||
// the reserve, giving away at most what the heap sizer allows.
|
||||
uint G1Policy::calculate_young_target_length(uint desired_young_length) const {
|
||||
uint allocated_young_length = _g1h->young_regions_count();
|
||||
|
||||
uint receiving_additional_eden;
|
||||
if (allocated_young_length >= desired_young_length) {
|
||||
// Already used up all we actually want (may happen as G1 revises the
|
||||
// young list length concurrently, or caused by gclocker). Do not allow more,
|
||||
// potentially resulting in GC.
|
||||
receiving_additional_eden = 0;
|
||||
log_trace(gc, ergo, heap)("Young target length: Already used up desired young %u allocated %u",
|
||||
desired_young_length,
|
||||
allocated_young_length);
|
||||
} else {
|
||||
// Now look at how many free regions are there currently, and the heap reserve.
|
||||
// We will try our best not to "eat" into the reserve as long as we can. If we
|
||||
// do, we at most eat the sizer's minimum regions into the reserve or half the
|
||||
// reserve rounded up (if possible; this is an arbitrary value).
|
||||
|
||||
uint max_to_eat_into_reserve = MIN2(_young_gen_sizer->min_desired_young_length(),
|
||||
(_reserve_regions + 1) / 2);
|
||||
|
||||
log_trace(gc, ergo, heap)("Young target length: Common "
|
||||
"free regions at end of collection %u "
|
||||
"desired young length %u "
|
||||
"reserve region %u "
|
||||
"max to eat into reserve %u",
|
||||
_free_regions_at_end_of_collection,
|
||||
desired_young_length,
|
||||
_reserve_regions,
|
||||
max_to_eat_into_reserve);
|
||||
|
||||
if (_free_regions_at_end_of_collection <= _reserve_regions) {
|
||||
// Fully eat (or already eating) into the reserve, hand back at most absolute_min_length regions.
|
||||
uint receiving_young = MIN3(_free_regions_at_end_of_collection,
|
||||
desired_young_length,
|
||||
max_to_eat_into_reserve);
|
||||
// We could already have allocated more regions than what we could get
|
||||
// above.
|
||||
receiving_additional_eden = allocated_young_length < receiving_young ?
|
||||
receiving_young - allocated_young_length : 0;
|
||||
|
||||
log_trace(gc, ergo, heap)("Young target length: Fully eat into reserve "
|
||||
"receiving young %u receiving additional eden %u",
|
||||
receiving_young,
|
||||
receiving_additional_eden);
|
||||
} else if (_free_regions_at_end_of_collection < (desired_young_length + _reserve_regions)) {
|
||||
// Partially eat into the reserve, at most max_to_eat_into_reserve regions.
|
||||
uint free_outside_reserve = _free_regions_at_end_of_collection - _reserve_regions;
|
||||
assert(free_outside_reserve < desired_young_length,
|
||||
"must be %u %u",
|
||||
free_outside_reserve, desired_young_length);
|
||||
|
||||
uint receiving_within_reserve = MIN2(desired_young_length - free_outside_reserve,
|
||||
max_to_eat_into_reserve);
|
||||
uint receiving_young = free_outside_reserve + receiving_within_reserve;
|
||||
// Again, we could have already allocated more than we could get.
|
||||
receiving_additional_eden = allocated_young_length < receiving_young ?
|
||||
receiving_young - allocated_young_length : 0;
|
||||
|
||||
log_trace(gc, ergo, heap)("Young target length: Partially eat into reserve "
|
||||
"free outside reserve %u "
|
||||
"receiving within reserve %u "
|
||||
"receiving young %u "
|
||||
"receiving additional eden %u",
|
||||
free_outside_reserve, receiving_within_reserve,
|
||||
receiving_young, receiving_additional_eden);
|
||||
} else {
|
||||
// No need to use the reserve.
|
||||
receiving_additional_eden = desired_young_length - allocated_young_length;
|
||||
log_trace(gc, ergo, heap)("Young target length: No need to use reserve "
|
||||
"receiving additional eden %u",
|
||||
receiving_additional_eden);
|
||||
}
|
||||
young_list_target_length = _young_list_fixed_length;
|
||||
}
|
||||
|
||||
uint target_young_length = allocated_young_length + receiving_additional_eden;
|
||||
result.second = young_list_target_length;
|
||||
|
||||
assert(target_young_length >= allocated_young_length, "must be");
|
||||
// We will try our best not to "eat" into the reserve.
|
||||
uint absolute_max_length = 0;
|
||||
if (_free_regions_at_end_of_collection > _reserve_regions) {
|
||||
absolute_max_length = _free_regions_at_end_of_collection - _reserve_regions;
|
||||
}
|
||||
if (desired_max_length > absolute_max_length) {
|
||||
desired_max_length = absolute_max_length;
|
||||
}
|
||||
|
||||
log_trace(gc, ergo, heap)("Young target length: "
|
||||
"young target length %u "
|
||||
"allocated young length %u "
|
||||
"received additional eden %u",
|
||||
target_young_length, allocated_young_length,
|
||||
receiving_additional_eden);
|
||||
return target_young_length;
|
||||
// Make sure we don't go over the desired max length, nor under the
|
||||
// desired min length. In case they clash, desired_min_length wins
|
||||
// which is why that test is second.
|
||||
if (young_list_target_length > desired_max_length) {
|
||||
young_list_target_length = desired_max_length;
|
||||
}
|
||||
if (young_list_target_length < desired_min_length) {
|
||||
young_list_target_length = desired_min_length;
|
||||
}
|
||||
|
||||
assert(young_list_target_length > base_min_length,
|
||||
"we should be able to allocate at least one eden region");
|
||||
assert(young_list_target_length >= absolute_min_length, "post-condition");
|
||||
|
||||
result.first = young_list_target_length;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint G1Policy::calculate_desired_eden_length_by_pause(double base_time_ms,
|
||||
uint min_eden_length,
|
||||
uint max_eden_length) const {
|
||||
uint G1Policy::calculate_young_list_target_length(size_t rs_length,
|
||||
uint base_min_length,
|
||||
uint desired_min_length,
|
||||
uint desired_max_length) const {
|
||||
assert(use_adaptive_young_list_length(), "pre-condition");
|
||||
assert(collector_state()->in_young_only_phase(), "only call this for young GCs");
|
||||
|
||||
assert(min_eden_length <= max_eden_length, "must be %u %u", min_eden_length, max_eden_length);
|
||||
// In case some edge-condition makes the desired max length too small...
|
||||
if (desired_max_length <= desired_min_length) {
|
||||
return desired_min_length;
|
||||
}
|
||||
|
||||
// We'll adjust min_young_length and max_young_length not to include
|
||||
// the already allocated young regions (i.e., so they reflect the
|
||||
// min and max eden regions we'll allocate). The base_min_length
|
||||
// will be reflected in the predictions by the
|
||||
// survivor_regions_evac_time prediction.
|
||||
assert(desired_min_length > base_min_length, "invariant");
|
||||
uint min_young_length = desired_min_length - base_min_length;
|
||||
assert(desired_max_length > base_min_length, "invariant");
|
||||
uint max_young_length = desired_max_length - base_min_length;
|
||||
|
||||
const double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
|
||||
const size_t pending_cards = _analytics->predict_pending_cards();
|
||||
const double base_time_ms = predict_base_elapsed_time_ms(pending_cards, rs_length);
|
||||
const uint available_free_regions = _free_regions_at_end_of_collection;
|
||||
const uint base_free_regions =
|
||||
available_free_regions > _reserve_regions ? available_free_regions - _reserve_regions : 0;
|
||||
|
||||
// Here, we will make sure that the shortest young length that
|
||||
// makes sense fits within the target pause time.
|
||||
|
||||
G1YoungLengthPredictor p(base_time_ms,
|
||||
_free_regions_at_end_of_collection,
|
||||
_mmu_tracker->max_gc_time() * 1000.0,
|
||||
base_free_regions,
|
||||
target_pause_time_ms,
|
||||
this);
|
||||
if (p.will_fit(min_eden_length)) {
|
||||
if (p.will_fit(min_young_length)) {
|
||||
// The shortest young length will fit into the target pause time;
|
||||
// we'll now check whether the absolute maximum number of young
|
||||
// regions will fit in the target pause time. If not, we'll do
|
||||
// a binary search between min_young_length and max_young_length.
|
||||
if (p.will_fit(max_eden_length)) {
|
||||
if (p.will_fit(max_young_length)) {
|
||||
// The maximum young length will fit into the target pause time.
|
||||
// We are done so set min young length to the maximum length (as
|
||||
// the result is assumed to be returned in min_young_length).
|
||||
min_eden_length = max_eden_length;
|
||||
min_young_length = max_young_length;
|
||||
} else {
|
||||
// The maximum possible number of young regions will not fit within
|
||||
// the target pause time so we'll search for the optimal
|
||||
@ -451,56 +357,37 @@ uint G1Policy::calculate_desired_eden_length_by_pause(double base_time_ms,
|
||||
// does, it becomes the new min. If it doesn't, it becomes
|
||||
// the new max. This way we maintain the loop invariants.
|
||||
|
||||
assert(min_eden_length < max_eden_length, "invariant");
|
||||
uint diff = (max_eden_length - min_eden_length) / 2;
|
||||
assert(min_young_length < max_young_length, "invariant");
|
||||
uint diff = (max_young_length - min_young_length) / 2;
|
||||
while (diff > 0) {
|
||||
uint eden_length = min_eden_length + diff;
|
||||
if (p.will_fit(eden_length)) {
|
||||
min_eden_length = eden_length;
|
||||
uint young_length = min_young_length + diff;
|
||||
if (p.will_fit(young_length)) {
|
||||
min_young_length = young_length;
|
||||
} else {
|
||||
max_eden_length = eden_length;
|
||||
max_young_length = young_length;
|
||||
}
|
||||
assert(min_eden_length < max_eden_length, "invariant");
|
||||
diff = (max_eden_length - min_eden_length) / 2;
|
||||
assert(min_young_length < max_young_length, "invariant");
|
||||
diff = (max_young_length - min_young_length) / 2;
|
||||
}
|
||||
// The results is min_young_length which, according to the
|
||||
// loop invariants, should fit within the target pause time.
|
||||
|
||||
// These are the post-conditions of the binary search above:
|
||||
assert(min_eden_length < max_eden_length,
|
||||
"otherwise we should have discovered that max_eden_length "
|
||||
assert(min_young_length < max_young_length,
|
||||
"otherwise we should have discovered that max_young_length "
|
||||
"fits into the pause target and not done the binary search");
|
||||
assert(p.will_fit(min_eden_length),
|
||||
"min_eden_length, the result of the binary search, should "
|
||||
assert(p.will_fit(min_young_length),
|
||||
"min_young_length, the result of the binary search, should "
|
||||
"fit into the pause target");
|
||||
assert(!p.will_fit(min_eden_length + 1),
|
||||
"min_eden_length, the result of the binary search, should be "
|
||||
assert(!p.will_fit(min_young_length + 1),
|
||||
"min_young_length, the result of the binary search, should be "
|
||||
"optimal, so no larger length should fit into the pause target");
|
||||
}
|
||||
} else {
|
||||
// Even the minimum length doesn't fit into the pause time
|
||||
// target, return it as the result nevertheless.
|
||||
}
|
||||
return min_eden_length;
|
||||
}
|
||||
|
||||
uint G1Policy::calculate_desired_eden_length_before_mixed(double survivor_base_time_ms,
|
||||
uint min_eden_length,
|
||||
uint max_eden_length) const {
|
||||
G1CollectionSetCandidates* candidates = _collection_set->candidates();
|
||||
|
||||
uint min_old_regions_end = MIN2(candidates->cur_idx() + calc_min_old_cset_length(), candidates->num_regions());
|
||||
double predicted_region_evac_time_ms = survivor_base_time_ms;
|
||||
for (uint i = candidates->cur_idx(); i < min_old_regions_end; i++) {
|
||||
HeapRegion* r = candidates->at(i);
|
||||
predicted_region_evac_time_ms += predict_region_total_time_ms(r, false);
|
||||
}
|
||||
uint desired_eden_length_by_min_cset_length =
|
||||
calculate_desired_eden_length_by_pause(predicted_region_evac_time_ms,
|
||||
min_eden_length,
|
||||
max_eden_length);
|
||||
|
||||
return desired_eden_length_by_min_cset_length;
|
||||
return base_min_length + min_young_length;
|
||||
}
|
||||
|
||||
double G1Policy::predict_survivor_regions_evac_time() const {
|
||||
@ -521,7 +408,8 @@ void G1Policy::revise_young_list_target_length_if_necessary(size_t rs_length) {
|
||||
// add 10% to avoid having to recalculate often
|
||||
size_t rs_length_prediction = rs_length * 1100 / 1000;
|
||||
update_rs_length_prediction(rs_length_prediction);
|
||||
update_young_length_bounds(rs_length_prediction);
|
||||
|
||||
update_young_list_max_and_target_length(rs_length_prediction);
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,7 +457,7 @@ void G1Policy::record_full_collection_end() {
|
||||
|
||||
_free_regions_at_end_of_collection = _g1h->num_free_regions();
|
||||
_survivor_surv_rate_group->reset();
|
||||
update_young_length_bounds();
|
||||
update_young_list_max_and_target_length();
|
||||
update_rs_length_prediction();
|
||||
|
||||
_old_gen_alloc_tracker.reset_after_full_gc();
|
||||
@ -899,11 +787,16 @@ void G1Policy::record_collection_pause_end(double pause_time_ms) {
|
||||
// Do not update dynamic IHOP due to G1 periodic collection as it is highly likely
|
||||
// that in this case we are not running in a "normal" operating mode.
|
||||
if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) {
|
||||
update_young_length_bounds();
|
||||
// IHOP control wants to know the expected young gen length if it were not
|
||||
// restrained by the heap reserve. Using the actual length would make the
|
||||
// prediction too small and the limit the young gen every time we get to the
|
||||
// predicted target occupancy.
|
||||
size_t last_unrestrained_young_length = update_young_list_max_and_target_length();
|
||||
|
||||
_old_gen_alloc_tracker.reset_after_young_gc(app_time_ms / 1000.0);
|
||||
update_ihop_prediction(_old_gen_alloc_tracker.last_cycle_duration(),
|
||||
_old_gen_alloc_tracker.last_cycle_old_bytes(),
|
||||
last_unrestrained_young_length * HeapRegion::GrainBytes,
|
||||
this_pause_was_young_only);
|
||||
|
||||
_ihop_control->send_trace_event(_g1h->gc_tracer_stw());
|
||||
@ -953,6 +846,7 @@ G1IHOPControl* G1Policy::create_ihop_control(const G1Predictions* predictor){
|
||||
|
||||
void G1Policy::update_ihop_prediction(double mutator_time_s,
|
||||
size_t mutator_alloc_bytes,
|
||||
size_t young_gen_size,
|
||||
bool this_gc_was_young_only) {
|
||||
// Always try to update IHOP prediction. Even evacuation failures give information
|
||||
// about e.g. whether to start IHOP earlier next time.
|
||||
@ -980,11 +874,6 @@ void G1Policy::update_ihop_prediction(double mutator_time_s,
|
||||
// marking, which makes any prediction useless. This increases the accuracy of the
|
||||
// prediction.
|
||||
if (this_gc_was_young_only && mutator_time_s > min_valid_time) {
|
||||
// IHOP control wants to know the expected young gen length if it were not
|
||||
// restrained by the heap reserve. Using the actual length would make the
|
||||
// prediction too small and the limit the young gen every time we get to the
|
||||
// predicted target occupancy.
|
||||
size_t young_gen_size = young_list_desired_length() * HeapRegion::GrainBytes;
|
||||
_ihop_control->update_allocation_info(mutator_time_s, mutator_alloc_bytes, young_gen_size);
|
||||
report = true;
|
||||
}
|
||||
@ -1091,7 +980,7 @@ void G1Policy::print_age_table() {
|
||||
_survivors_age_table.print_age_table(_tenuring_threshold);
|
||||
}
|
||||
|
||||
uint G1Policy::calculate_young_max_length(uint target_young_length) const {
|
||||
void G1Policy::update_max_gc_locker_expansion() {
|
||||
uint expansion_region_num = 0;
|
||||
if (GCLockerEdenExpansionPercent > 0) {
|
||||
double perc = (double) GCLockerEdenExpansionPercent / 100.0;
|
||||
@ -1102,9 +991,8 @@ uint G1Policy::calculate_young_max_length(uint target_young_length) const {
|
||||
} else {
|
||||
assert(expansion_region_num == 0, "sanity");
|
||||
}
|
||||
uint max_length = target_young_length + expansion_region_num;
|
||||
assert(target_young_length <= max_length, "post-condition");
|
||||
return max_length;
|
||||
_young_list_max_length = _young_list_target_length + expansion_region_num;
|
||||
assert(_young_list_target_length <= _young_list_max_length, "post-condition");
|
||||
}
|
||||
|
||||
// Calculates survivor space parameters.
|
||||
@ -1313,10 +1201,8 @@ bool G1Policy::next_gc_should_be_mixed(const char* true_action_str,
|
||||
const char* false_action_str) const {
|
||||
G1CollectionSetCandidates* candidates = _collection_set->candidates();
|
||||
|
||||
if (candidates == NULL || candidates->is_empty()) {
|
||||
if (false_action_str != NULL) {
|
||||
log_debug(gc, ergo)("%s (candidate old regions not available)", false_action_str);
|
||||
}
|
||||
if (candidates->is_empty()) {
|
||||
log_debug(gc, ergo)("%s (candidate old regions not available)", false_action_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1325,16 +1211,12 @@ bool G1Policy::next_gc_should_be_mixed(const char* true_action_str,
|
||||
double reclaimable_percent = reclaimable_bytes_percent(reclaimable_bytes);
|
||||
double threshold = (double) G1HeapWastePercent;
|
||||
if (reclaimable_percent <= threshold) {
|
||||
if (false_action_str != NULL) {
|
||||
log_debug(gc, ergo)("%s (reclaimable percentage not over threshold). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT,
|
||||
false_action_str, candidates->num_remaining(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent);
|
||||
}
|
||||
log_debug(gc, ergo)("%s (reclaimable percentage not over threshold). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT,
|
||||
false_action_str, candidates->num_remaining(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent);
|
||||
return false;
|
||||
}
|
||||
if (true_action_str != NULL) {
|
||||
log_debug(gc, ergo)("%s (candidate old regions available). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT,
|
||||
true_action_str, candidates->num_remaining(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent);
|
||||
}
|
||||
log_debug(gc, ergo)("%s (candidate old regions available). candidate old regions: %u reclaimable: " SIZE_FORMAT " (%1.2f) threshold: " UINTX_FORMAT,
|
||||
true_action_str, candidates->num_remaining(), reclaimable_bytes, reclaimable_percent, G1HeapWastePercent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ class G1Policy: public CHeapObj<mtGC> {
|
||||
// Update the IHOP control with necessary statistics.
|
||||
void update_ihop_prediction(double mutator_time_s,
|
||||
size_t mutator_alloc_bytes,
|
||||
size_t young_gen_size,
|
||||
bool this_gc_was_young_only);
|
||||
void report_ihop_statistics();
|
||||
|
||||
@ -75,8 +76,8 @@ class G1Policy: public CHeapObj<mtGC> {
|
||||
|
||||
jlong _collection_pause_end_millis;
|
||||
|
||||
uint _young_list_desired_length;
|
||||
uint _young_list_target_length;
|
||||
uint _young_list_fixed_length;
|
||||
|
||||
// The max number of regions we can extend the eden by while the GC
|
||||
// locker is active. This should be >= _young_list_target_length;
|
||||
@ -169,10 +170,6 @@ public:
|
||||
|
||||
private:
|
||||
G1CollectionSet* _collection_set;
|
||||
|
||||
bool next_gc_should_be_mixed(const char* true_action_str,
|
||||
const char* false_action_str) const;
|
||||
|
||||
double average_time_ms(G1GCPhaseTimes::GCParPhases phase) const;
|
||||
double other_time_ms(double pause_time_ms) const;
|
||||
|
||||
@ -192,38 +189,44 @@ private:
|
||||
double _mark_remark_start_sec;
|
||||
double _mark_cleanup_start_sec;
|
||||
|
||||
// Updates the internal young gen maximum and target and desired lengths.
|
||||
// If no rs_length parameter is passed, predict the RS length using the
|
||||
// prediction model, otherwise use the given rs_length as the prediction.
|
||||
void update_young_length_bounds();
|
||||
void update_young_length_bounds(size_t rs_length);
|
||||
// Updates the internal young list maximum and target lengths. Returns the
|
||||
// unbounded young list target length. If no rs_length parameter is passed,
|
||||
// predict the RS length using the prediction model, otherwise use the
|
||||
// given rs_length as the prediction.
|
||||
uint update_young_list_max_and_target_length();
|
||||
uint update_young_list_max_and_target_length(size_t rs_length);
|
||||
|
||||
// Calculate and return the minimum desired eden length based on the MMU target.
|
||||
uint calculate_desired_eden_length_by_mmu() const;
|
||||
// Update the young list target length either by setting it to the
|
||||
// desired fixed value or by calculating it using G1's pause
|
||||
// prediction model.
|
||||
// Returns the unbounded young list target length.
|
||||
uint update_young_list_target_length(size_t rs_length);
|
||||
|
||||
// Calculate and return the desired eden length that can fit into the pause time goal.
|
||||
// The parameters are: rs_length represents the prediction of how large the
|
||||
// young RSet lengths will be, min_eden_length and max_eden_length are the bounds
|
||||
// (inclusive) within eden can grow.
|
||||
uint calculate_desired_eden_length_by_pause(double base_time_ms,
|
||||
uint min_eden_length,
|
||||
uint max_eden_length) const;
|
||||
// Calculate and return the minimum desired young list target
|
||||
// length. This is the minimum desired young list length according
|
||||
// to the user's inputs.
|
||||
uint calculate_young_list_desired_min_length(uint base_min_length) const;
|
||||
|
||||
// Calculates the desired eden length before mixed gc so that after adding the
|
||||
// minimum amount of old gen regions from the collection set, the eden fits into
|
||||
// the pause time goal.
|
||||
uint calculate_desired_eden_length_before_mixed(double survivor_base_time_ms,
|
||||
uint min_eden_length,
|
||||
uint max_eden_length) const;
|
||||
// Calculate and return the maximum desired young list target
|
||||
// length. This is the maximum desired young list length according
|
||||
// to the user's inputs.
|
||||
uint calculate_young_list_desired_max_length() const;
|
||||
|
||||
// Calculate desired young length based on current situation without taking actually
|
||||
// available free regions into account.
|
||||
uint calculate_young_desired_length(size_t rs_length) const;
|
||||
// Limit the given desired young length to available free regions.
|
||||
uint calculate_young_target_length(uint desired_young_length) const;
|
||||
// The GCLocker might cause us to need more regions than the target. Calculate
|
||||
// the maximum number of regions to use in that case.
|
||||
uint calculate_young_max_length(uint target_young_length) const;
|
||||
// Calculate and return the maximum young list target length that
|
||||
// can fit into the pause time goal. The parameters are: rs_length
|
||||
// represent the prediction of how large the young RSet lengths will
|
||||
// be, base_min_length is the already existing number of regions in
|
||||
// the young list, min_length and max_length are the desired min and
|
||||
// max young list length according to the user's inputs.
|
||||
uint calculate_young_list_target_length(size_t rs_length,
|
||||
uint base_min_length,
|
||||
uint desired_min_length,
|
||||
uint desired_max_length) const;
|
||||
|
||||
// Result of the bounded_young_list_target_length() method, containing both the
|
||||
// bounded as well as the unbounded young list target lengths in this order.
|
||||
typedef Pair<uint, uint, StackObj> YoungTargetLengths;
|
||||
YoungTargetLengths young_list_target_lengths(size_t rs_length) const;
|
||||
|
||||
void update_rs_length_prediction();
|
||||
void update_rs_length_prediction(size_t prediction);
|
||||
@ -332,6 +335,9 @@ public:
|
||||
|
||||
void print_phases();
|
||||
|
||||
bool next_gc_should_be_mixed(const char* true_action_str,
|
||||
const char* false_action_str) const;
|
||||
|
||||
// Calculate and return the number of initial and optional old gen regions from
|
||||
// the given collection set candidates and the remaining time.
|
||||
void calculate_old_collection_set_regions(G1CollectionSetCandidates* candidates,
|
||||
@ -368,7 +374,6 @@ public:
|
||||
// the initial-mark work and start a marking cycle.
|
||||
void decide_on_conc_mark_initiation();
|
||||
|
||||
uint young_list_desired_length() const { return _young_list_desired_length; }
|
||||
size_t young_list_target_length() const { return _young_list_target_length; }
|
||||
|
||||
bool should_allocate_mutator_region() const;
|
||||
@ -429,6 +434,8 @@ public:
|
||||
|
||||
void print_age_table();
|
||||
|
||||
void update_max_gc_locker_expansion();
|
||||
|
||||
void update_survivors_policy();
|
||||
|
||||
virtual bool force_upgrade_to_full() {
|
||||
|
Loading…
Reference in New Issue
Block a user