--- old/src/hotspot/share/gc/g1/g1Analytics.cpp 2020-06-15 11:18:29.724508773 +0200 +++ new/src/hotspot/share/gc/g1/g1Analytics.cpp 2020-06-15 11:18:29.632507603 +0200 @@ -224,7 +224,11 @@ } double G1Analytics::predict_alloc_rate_ms() const { - return predict_zero_bounded(_alloc_rate_ms_seq); + if (enough_samples_available(_alloc_rate_ms_seq)) { + return predict_zero_bounded(_alloc_rate_ms_seq); + } else { + return 0.0; + } } double G1Analytics::predict_concurrent_refine_rate_ms() const { --- old/src/hotspot/share/gc/g1/g1Policy.cpp 2020-06-15 11:18:30.160514323 +0200 +++ new/src/hotspot/share/gc/g1/g1Policy.cpp 2020-06-15 11:18:30.072513204 +0200 @@ -46,6 +46,7 @@ #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" @@ -61,8 +62,8 @@ _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()), @@ -107,14 +108,11 @@ 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_list_max_and_target_length(); + update_young_length_bounds(); // 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(); @@ -189,158 +187,254 @@ _ihop_control->update_target_occupancy(new_number_of_regions * HeapRegion::GrainBytes); } -uint G1Policy::calculate_young_list_desired_min_length(uint base_min_length) const { +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 desired_min_length = 0; if (use_adaptive_young_list_length()) { - 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 - } - } - 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); -} - -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(); -} - -uint G1Policy::update_young_list_max_and_target_length() { - return update_young_list_max_and_target_length(_analytics->predict_rs_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; -} - -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; - - return young_lengths.second; -} - -G1Policy::YoungTargetLengths G1Policy::young_list_target_lengths(size_t rs_length) const { - YoungTargetLengths result; + 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); + } + return desired_min_length; +} + +void G1Policy::update_young_length_bounds() { + update_young_length_bounds(_analytics->predict_rs_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); +} + +// 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(); + + assert(min_young_length_by_sizer >= 1, "invariant"); + assert(max_young_length_by_sizer >= min_young_length_by_sizer, "invariant"); + + // 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; // Calculate the absolute and desired min bounds first. - // 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. + // 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); + + 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 young_list_target_length = 0; + uint desired_young_length = 0; if (use_adaptive_young_list_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); + 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); } else { - // 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. + 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); } + // 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. - young_list_target_length = _young_list_fixed_length; - } - - result.second = young_list_target_length; - - // 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; + 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); - // 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; + 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); + } } - 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"); + uint target_young_length = allocated_young_length + receiving_additional_eden; - result.first = young_list_target_length; - return result; -} + assert(target_young_length >= allocated_young_length, "must be"); -uint G1Policy::calculate_young_list_target_length(size_t rs_length, - uint base_min_length, - uint desired_min_length, - uint desired_max_length) const { + 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; +} + +uint G1Policy::calculate_desired_eden_length_by_pause(double base_time_ms, + uint min_eden_length, + uint max_eden_length) const { assert(use_adaptive_young_list_length(), "pre-condition"); - assert(collector_state()->in_young_only_phase(), "only call this for young GCs"); - // 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; + assert(min_eden_length <= max_eden_length, "must be %u %u", min_eden_length, max_eden_length); // Here, we will make sure that the shortest young length that // makes sense fits within the target pause time. G1YoungLengthPredictor p(base_time_ms, - base_free_regions, - target_pause_time_ms, + _free_regions_at_end_of_collection, + _mmu_tracker->max_gc_time() * 1000.0, this); - if (p.will_fit(min_young_length)) { + if (p.will_fit(min_eden_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_young_length)) { + if (p.will_fit(max_eden_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_young_length = max_young_length; + min_eden_length = max_eden_length; } else { // The maximum possible number of young regions will not fit within // the target pause time so we'll search for the optimal @@ -357,37 +451,56 @@ // does, it becomes the new min. If it doesn't, it becomes // the new max. This way we maintain the loop invariants. - assert(min_young_length < max_young_length, "invariant"); - uint diff = (max_young_length - min_young_length) / 2; + assert(min_eden_length < max_eden_length, "invariant"); + uint diff = (max_eden_length - min_eden_length) / 2; while (diff > 0) { - uint young_length = min_young_length + diff; - if (p.will_fit(young_length)) { - min_young_length = young_length; + uint eden_length = min_eden_length + diff; + if (p.will_fit(eden_length)) { + min_eden_length = eden_length; } else { - max_young_length = young_length; + max_eden_length = eden_length; } - assert(min_young_length < max_young_length, "invariant"); - diff = (max_young_length - min_young_length) / 2; + assert(min_eden_length < max_eden_length, "invariant"); + diff = (max_eden_length - min_eden_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_young_length < max_young_length, - "otherwise we should have discovered that max_young_length " + assert(min_eden_length < max_eden_length, + "otherwise we should have discovered that max_eden_length " "fits into the pause target and not done the binary search"); - assert(p.will_fit(min_young_length), - "min_young_length, the result of the binary search, should " + assert(p.will_fit(min_eden_length), + "min_eden_length, the result of the binary search, should " "fit into the pause target"); - assert(!p.will_fit(min_young_length + 1), - "min_young_length, the result of the binary search, should be " + assert(!p.will_fit(min_eden_length + 1), + "min_eden_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 base_min_length + min_young_length; + 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; } double G1Policy::predict_survivor_regions_evac_time() const { @@ -408,8 +521,7 @@ // 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_list_max_and_target_length(rs_length_prediction); + update_young_length_bounds(rs_length_prediction); } } @@ -457,7 +569,7 @@ _free_regions_at_end_of_collection = _g1h->num_free_regions(); _survivor_surv_rate_group->reset(); - update_young_list_max_and_target_length(); + update_young_length_bounds(); update_rs_length_prediction(); _old_gen_alloc_tracker.reset_after_full_gc(); @@ -787,16 +899,11 @@ // 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) { - // 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(); + update_young_length_bounds(); _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()); @@ -846,7 +953,6 @@ 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. @@ -874,6 +980,11 @@ // 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. + uint 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; } @@ -980,7 +1091,7 @@ _survivors_age_table.print_age_table(_tenuring_threshold); } -void G1Policy::update_max_gc_locker_expansion() { +uint G1Policy::calculate_young_max_length(uint target_young_length) const { uint expansion_region_num = 0; if (GCLockerEdenExpansionPercent > 0) { double perc = (double) GCLockerEdenExpansionPercent / 100.0; @@ -991,8 +1102,9 @@ } else { assert(expansion_region_num == 0, "sanity"); } - _young_list_max_length = _young_list_target_length + expansion_region_num; - assert(_young_list_target_length <= _young_list_max_length, "post-condition"); + uint max_length = target_young_length + expansion_region_num; + assert(target_young_length <= max_length, "post-condition"); + return max_length; } // Calculates survivor space parameters. @@ -1201,8 +1313,10 @@ const char* false_action_str) const { G1CollectionSetCandidates* candidates = _collection_set->candidates(); - if (candidates->is_empty()) { - log_debug(gc, ergo)("%s (candidate old regions not available)", false_action_str); + if (candidates == NULL || candidates->is_empty()) { + if (false_action_str != NULL) { + log_debug(gc, ergo)("%s (candidate old regions not available)", false_action_str); + } return false; } @@ -1211,12 +1325,16 @@ double reclaimable_percent = reclaimable_bytes_percent(reclaimable_bytes); double threshold = (double) G1HeapWastePercent; if (reclaimable_percent <= threshold) { - 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); + 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); + } return false; } - 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); + 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); + } return true; } --- old/src/hotspot/share/gc/g1/g1Policy.hpp 2020-06-15 11:18:30.652520586 +0200 +++ new/src/hotspot/share/gc/g1/g1Policy.hpp 2020-06-15 11:18:30.556519363 +0200 @@ -60,7 +60,6 @@ // 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(); @@ -76,8 +75,8 @@ 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; @@ -170,6 +169,10 @@ 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; @@ -189,44 +192,38 @@ double _mark_remark_start_sec; double _mark_cleanup_start_sec; - // 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); - - // 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 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; - - // 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 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 YoungTargetLengths; - YoungTargetLengths young_list_target_lengths(size_t rs_length) const; + // 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); + + // Calculate and return the minimum desired eden length based on the MMU target. + uint calculate_desired_eden_length_by_mmu() const; + + // 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; + + // 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 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; void update_rs_length_prediction(); void update_rs_length_prediction(size_t prediction); @@ -335,9 +332,6 @@ 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, @@ -374,6 +368,7 @@ // 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; @@ -434,8 +429,6 @@ void print_age_table(); - void update_max_gc_locker_expansion(); - void update_survivors_policy(); virtual bool force_upgrade_to_full() {