--- old/src/hotspot/share/gc/g1/g1Analytics.cpp 2020-06-15 11:18:25.040449147 +0200 +++ new/src/hotspot/share/gc/g1/g1Analytics.cpp 2020-06-15 11:18:24.944447924 +0200 @@ -224,7 +224,7 @@ } double G1Analytics::predict_alloc_rate_ms() const { - if (!enough_samples_available(_alloc_rate_ms_seq)) { + if (enough_samples_available(_alloc_rate_ms_seq)) { return predict_zero_bounded(_alloc_rate_ms_seq); } else { return 0.0; --- old/src/hotspot/share/gc/g1/g1Policy.cpp 2020-06-15 11:18:25.484454799 +0200 +++ new/src/hotspot/share/gc/g1/g1Policy.cpp 2020-06-15 11:18:25.388453577 +0200 @@ -62,6 +62,7 @@ _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_max_length(0), _eden_surv_rate_group(new G1SurvRateGroup()), @@ -111,7 +112,7 @@ _free_regions_at_end_of_collection = _g1h->num_free_regions(); - update_young_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(); @@ -200,23 +201,19 @@ return desired_min_length; } -uint G1Policy::update_young_max_and_target_length() { - return update_young_max_and_target_length(_analytics->predict_rs_length()); +void G1Policy::update_young_length_bounds() { + update_young_length_bounds(_analytics->predict_rs_length()); } -uint G1Policy::update_young_max_and_target_length(size_t rs_length) { - uint unbounded_target_length = update_young_target_length(rs_length); - update_max_gc_locker_expansion(); - return unbounded_target_length; -} - -uint G1Policy::update_young_target_length(size_t rs_length) { - uint desired_length = calculate_young_desired_length(rs_length); - _young_list_target_length = calculate_young_target_length(desired_length); - - log_debug(gc,ergo,heap)("Young target lengths: desired: %u target: %u", - desired_length, _young_list_target_length); - return desired_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: @@ -226,6 +223,12 @@ // - 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(); @@ -233,7 +236,7 @@ assert(min_young_length_by_sizer >= 1, "invariant"); assert(max_young_length_by_sizer >= min_young_length_by_sizer, "invariant"); - // Absolute minimum eden length. See above why. + // 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. @@ -271,7 +274,7 @@ absolute_min_young_length - survivor_length, absolute_max_young_length - survivor_length); } else { - desired_eden_length_before_mixed = + 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); @@ -518,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_max_and_target_length(rs_length_prediction); + update_young_length_bounds(rs_length_prediction); } } @@ -567,7 +569,7 @@ _free_regions_at_end_of_collection = _g1h->num_free_regions(); _survivor_surv_rate_group->reset(); - update_young_max_and_target_length(); + update_young_length_bounds(); update_rs_length_prediction(); _old_gen_alloc_tracker.reset_after_full_gc(); @@ -897,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_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()); @@ -956,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. @@ -984,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; } @@ -1090,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; @@ -1101,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. --- old/src/hotspot/share/gc/g1/g1Policy.hpp 2020-06-15 11:18:25.968460961 +0200 +++ new/src/hotspot/share/gc/g1/g1Policy.hpp 2020-06-15 11:18:25.872459739 +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,6 +75,7 @@ jlong _collection_pause_end_millis; + uint _young_list_desired_length; uint _young_list_target_length; // The max number of regions we can extend the eden by while the GC @@ -192,18 +192,11 @@ double _mark_remark_start_sec; double _mark_cleanup_start_sec; - // Updates the internal young gen maximum and target lengths. Returns the - // unbounded young 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_max_and_target_length(); - uint update_young_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_target_length(size_t rs_length); + // 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; @@ -228,6 +221,9 @@ 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); @@ -372,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; @@ -432,8 +429,6 @@ void print_age_table(); - void update_max_gc_locker_expansion(); - void update_survivors_policy(); virtual bool force_upgrade_to_full() {