< prev index next >
src/hotspot/share/gc/g1/g1Policy.cpp
Print this page
rev 59792 : imported patch 8244603-sjohanss-review
*** 60,69 ****
--- 60,70 ----
_mmu_tracker(new G1MMUTrackerQueue(GCPauseIntervalMillis / 1000.0, MaxGCPauseMillis / 1000.0)),
_ihop_control(create_ihop_control(&_predictor)),
_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()),
_survivor_surv_rate_group(new G1SurvRateGroup()),
_reserve_factor((double) G1ReservePercent / 100.0),
*** 109,119 ****
_young_gen_sizer->adjust_max_new_size(_g1h->max_expandable_regions());
_free_regions_at_end_of_collection = _g1h->num_free_regions();
! update_young_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();
}
--- 110,120 ----
_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();
// 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();
}
*** 198,241 ****
desired_min_length = (uint) ceil(alloc_rate_ms * when_ms);
}
return desired_min_length;
}
! uint G1Policy::update_young_max_and_target_length() {
! return update_young_max_and_target_length(_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;
}
// 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.
//
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. See above why.
// 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;
--- 199,244 ----
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;
*** 516,527 ****
if (rs_length > _rs_length_prediction) {
// 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);
}
}
void G1Policy::update_rs_length_prediction() {
update_rs_length_prediction(_analytics->predict_rs_length());
--- 519,529 ----
if (rs_length > _rs_length_prediction) {
// 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);
}
}
void G1Policy::update_rs_length_prediction() {
update_rs_length_prediction(_analytics->predict_rs_length());
*** 565,575 ****
_eden_surv_rate_group->start_adding_regions();
// also call this on any additional surv rate groups
_free_regions_at_end_of_collection = _g1h->num_free_regions();
_survivor_surv_rate_group->reset();
! update_young_max_and_target_length();
update_rs_length_prediction();
_old_gen_alloc_tracker.reset_after_full_gc();
record_pause(FullGC, _full_collection_start_sec, end_sec);
--- 567,577 ----
_eden_surv_rate_group->start_adding_regions();
// also call this on any additional surv rate groups
_free_regions_at_end_of_collection = _g1h->num_free_regions();
_survivor_surv_rate_group->reset();
! update_young_length_bounds();
update_rs_length_prediction();
_old_gen_alloc_tracker.reset_after_full_gc();
record_pause(FullGC, _full_collection_start_sec, end_sec);
*** 895,914 ****
update_rs_length_prediction();
// 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();
_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());
} else {
// Any garbage collection triggered as periodic collection resets the time-to-mixed
--- 897,911 ----
update_rs_length_prediction();
// 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();
_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(),
this_pause_was_young_only);
_ihop_control->send_trace_event(_g1h->gc_tracer_stw());
} else {
// Any garbage collection triggered as periodic collection resets the time-to-mixed
*** 954,964 ****
}
}
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.
// Avoid using really small application times that might create samples with
--- 951,960 ----
*** 982,991 ****
--- 978,992 ----
// As an approximation for the young gc promotion rates during marking we use
// all of them. In many applications there are only a few if any young gcs during
// 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;
}
if (report) {
*** 1088,1110 ****
void G1Policy::print_age_table() {
_survivors_age_table.print_age_table(_tenuring_threshold);
}
! void G1Policy::update_max_gc_locker_expansion() {
uint expansion_region_num = 0;
if (GCLockerEdenExpansionPercent > 0) {
double perc = (double) GCLockerEdenExpansionPercent / 100.0;
double expansion_region_num_d = perc * (double) _young_list_target_length;
// We use ceiling so that if expansion_region_num_d is > 0.0 (but
// less than 1.0) we'll get 1.
expansion_region_num = (uint) ceil(expansion_region_num_d);
} 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");
}
// Calculates survivor space parameters.
void G1Policy::update_survivors_policy() {
double max_survivor_regions_d =
--- 1089,1112 ----
void G1Policy::print_age_table() {
_survivors_age_table.print_age_table(_tenuring_threshold);
}
! 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;
double expansion_region_num_d = perc * (double) _young_list_target_length;
// We use ceiling so that if expansion_region_num_d is > 0.0 (but
// less than 1.0) we'll get 1.
expansion_region_num = (uint) ceil(expansion_region_num_d);
} 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;
}
// Calculates survivor space parameters.
void G1Policy::update_survivors_policy() {
double max_survivor_regions_d =
< prev index next >