--- old/src/share/vm/gc/g1/g1IHOPControl.cpp 2015-11-17 14:15:42.407953248 +0100 +++ new/src/share/vm/gc/g1/g1IHOPControl.cpp 2015-11-17 14:15:42.320950656 +0100 @@ -100,27 +100,35 @@ } #endif -G1AdaptiveIHOPControl::G1AdaptiveIHOPControl(double ihop_percent, size_t initial_target_occupancy, G1Predictions const* predictor) : +G1AdaptiveIHOPControl::G1AdaptiveIHOPControl(double ihop_percent, + size_t initial_target_occupancy, + G1Predictions const* predictor, + size_t heap_reserve_percent, + size_t heap_waste_percent) : G1IHOPControl(ihop_percent, initial_target_occupancy), _predictor(predictor), _marking_times_s(10, 0.95), _allocation_rate_s(10, 0.95), - _prev_unrestrained_young_size(0), - _current_threshold(0.0) + _last_unrestrained_young_size(0), + _current_threshold(0.0), + _heap_reserve_percent(heap_reserve_percent), + _heap_waste_percent(heap_waste_percent) { - recalculate(); + calculate(); } -void G1AdaptiveIHOPControl::recalculate() { +void G1AdaptiveIHOPControl::calculate() { if (have_enough_data_for_prediction()) { double pred_marking_time = _predictor->get_new_prediction(&_marking_times_s); double pred_promotion_rate = _predictor->get_new_prediction(&_allocation_rate_s); size_t predicted_needed_bytes_during_marking = (pred_marking_time * pred_promotion_rate + - _prev_unrestrained_young_size); // In reality we would need the size of the young gen of the first mixed GC. This is a conservative estimate. - size_t predicted_initiating_threshold = predicted_needed_bytes_during_marking < _target_occupancy ? - _target_occupancy - predicted_needed_bytes_during_marking : + _last_unrestrained_young_size); // In reality we would need the maximum size of the young gen during marking. This is a conservative estimate. + + size_t internal_threshold = actual_target_threshold(); + size_t predicted_initiating_threshold = predicted_needed_bytes_during_marking < internal_threshold ? + internal_threshold - predicted_needed_bytes_during_marking : 0; _current_threshold = predicted_initiating_threshold; } else { @@ -129,6 +137,23 @@ } } +size_t G1AdaptiveIHOPControl::actual_target_threshold() const { + // The actual target threshold takes the heap reserve and the expected waste in + // free space into account. + // _heap_reserve is that part of the total heap capacity that is reserved for + // eventual promotion failure. + // _heap_waste is the amount of space will never be reclaimed in any + // heap, so can not be used for allocation during marking and must always be + // considered. + + double safe_total_heap_percentage = MIN2((double)(_heap_reserve_percent + _heap_waste_percent), 100.0); + + return MIN2( + G1CollectedHeap::heap()->max_capacity() * (100.0 - safe_total_heap_percentage) / 100.0, + _target_occupancy * (100.0 - _heap_waste_percent) / 100.0 + ); +} + bool G1AdaptiveIHOPControl::have_enough_data_for_prediction() const { return ((size_t)_marking_times_s.num() >= G1AdaptiveIHOPNumInitialSamples) && ((size_t)_allocation_rate_s.num() >= G1AdaptiveIHOPNumInitialSamples); @@ -139,7 +164,7 @@ } size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() { - recalculate(); + calculate(); return _current_threshold; } @@ -149,7 +174,7 @@ _allocation_rate_s.add(allocation_rate); _last_allocation_bytes = allocated_bytes; - _prev_unrestrained_young_size = additional_buffer_size; + _last_unrestrained_young_size = additional_buffer_size; } void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { @@ -157,6 +182,10 @@ _marking_times_s.add(marking_length_s); } +static double percentage_of(double quantity, double base_quantity) { + return base_quantity > 0.0 ? (quantity / base_quantity) * 100.0 : 0.0; +} + void G1AdaptiveIHOPControl::print() { ergo_verbose6(ErgoIHOP, "basic information", @@ -167,18 +196,24 @@ ergo_format_double("recent old gen allocation rate") ergo_format_double("recent marking phase length"), get_conc_mark_start_threshold(), - _target_occupancy > 0 ? (double) get_conc_mark_start_threshold() / _target_occupancy * 100.0 : 0.0, + percentage_of(get_conc_mark_start_threshold(), _target_occupancy), _target_occupancy, G1CollectedHeap::heap()->used(), _allocation_rate_s.last(), _marking_times_s.last() ); - ergo_verbose3(ErgoIHOP, + size_t actual_target = actual_target_threshold(); + ergo_verbose6(ErgoIHOP, "adaptive IHOP information", ergo_format_reason("value update") + ergo_format_byte_perc("threshold") + ergo_format_byte("internal target occupancy") ergo_format_double("predicted old gen allocation rate") ergo_format_double("predicted marking phase length") ergo_format_str("prediction active"), + get_conc_mark_start_threshold(), + percentage_of(get_conc_mark_start_threshold(), actual_target), + actual_target, _predictor->get_new_prediction(&_allocation_rate_s), _predictor->get_new_prediction(&_marking_times_s), have_enough_data_for_prediction() ? "true" : "false" @@ -195,7 +230,7 @@ // target_size - (young_size + alloc_amount/alloc_time * marking_time) G1Predictions pred(0.95); - G1AdaptiveIHOPControl ctrl(initial_threshold, target_size, &pred); + G1AdaptiveIHOPControl ctrl(initial_threshold, target_size, &pred, 0, 0); // First "load". size_t const alloc_time1 = 2; @@ -238,7 +273,7 @@ size_t const alloc_time3 = 1; size_t const alloc_amount3 = 50; size_t const marking_time3 = 2; - size_t const settled_ihop3 = 0; // target_size - (young_size + alloc_amount2/alloc_time2 * marking_time2); + size_t const settled_ihop3 = 0; test_update(&ctrl, alloc_time3, alloc_amount3, young_size, marking_time3); threshold = ctrl.get_conc_mark_start_threshold();