Mon, 04 Mar 2013 12:42:14 -0800
8007036: G1: Too many old regions added to last mixed GC
Summary: Stop adding old regions to collection set when the remaining reclaimable bytes reaches, or goes below, G1HeapWastePercent. Changes were also reviewed by Vitaly Davidovich <vitalyd@gmail.com>.
Reviewed-by: brutisso
1.1 --- a/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Mon Mar 04 13:01:24 2013 +0100 1.2 +++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Mon Mar 04 12:42:14 2013 -0800 1.3 @@ -146,43 +146,6 @@ 1.4 verify(); 1.5 } 1.6 1.7 -uint CollectionSetChooser::calc_min_old_cset_length() { 1.8 - // The min old CSet region bound is based on the maximum desired 1.9 - // number of mixed GCs after a cycle. I.e., even if some old regions 1.10 - // look expensive, we should add them to the CSet anyway to make 1.11 - // sure we go through the available old regions in no more than the 1.12 - // maximum desired number of mixed GCs. 1.13 - // 1.14 - // The calculation is based on the number of marked regions we added 1.15 - // to the CSet chooser in the first place, not how many remain, so 1.16 - // that the result is the same during all mixed GCs that follow a cycle. 1.17 - 1.18 - const size_t region_num = (size_t) _length; 1.19 - const size_t gc_num = (size_t) G1MixedGCCountTarget; 1.20 - size_t result = region_num / gc_num; 1.21 - // emulate ceiling 1.22 - if (result * gc_num < region_num) { 1.23 - result += 1; 1.24 - } 1.25 - return (uint) result; 1.26 -} 1.27 - 1.28 -uint CollectionSetChooser::calc_max_old_cset_length() { 1.29 - // The max old CSet region bound is based on the threshold expressed 1.30 - // as a percentage of the heap size. I.e., it should bound the 1.31 - // number of old regions added to the CSet irrespective of how many 1.32 - // of them are available. 1.33 - 1.34 - G1CollectedHeap* g1h = G1CollectedHeap::heap(); 1.35 - const size_t region_num = g1h->n_regions(); 1.36 - const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; 1.37 - size_t result = region_num * perc / 100; 1.38 - // emulate ceiling 1.39 - if (100 * result < region_num * perc) { 1.40 - result += 1; 1.41 - } 1.42 - return (uint) result; 1.43 -} 1.44 1.45 void CollectionSetChooser::add_region(HeapRegion* hr) { 1.46 assert(!hr->isHumongous(),
2.1 --- a/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp Mon Mar 04 13:01:24 2013 +0100 2.2 +++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp Mon Mar 04 12:42:14 2013 -0800 2.3 @@ -51,6 +51,8 @@ 2.4 uint _curr_index; 2.5 2.6 // The number of candidate old regions added to the CSet chooser. 2.7 + // Note: this is not updated when removing a region using 2.8 + // remove_and_move_to_next() below. 2.9 uint _length; 2.10 2.11 // Keeps track of the start of the next array chunk to be claimed by 2.12 @@ -111,13 +113,8 @@ 2.13 hr->live_bytes() < _region_live_threshold_bytes; 2.14 } 2.15 2.16 - // Calculate the minimum number of old regions we'll add to the CSet 2.17 - // during a mixed GC. 2.18 - uint calc_min_old_cset_length(); 2.19 - 2.20 - // Calculate the maximum number of old regions we'll add to the CSet 2.21 - // during a mixed GC. 2.22 - uint calc_max_old_cset_length(); 2.23 + // Returns the number candidate old regions added 2.24 + uint length() { return _length; } 2.25 2.26 // Serial version. 2.27 void add_region(HeapRegion *hr);
3.1 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Mar 04 13:01:24 2013 +0100 3.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Mar 04 12:42:14 2013 -0800 3.3 @@ -1806,6 +1806,14 @@ 3.4 } 3.5 #endif // !PRODUCT 3.6 3.7 +double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) { 3.8 + // Returns the given amount of reclaimable bytes (that represents 3.9 + // the amount of reclaimable space still to be collected) as a 3.10 + // percentage of the current heap capacity. 3.11 + size_t capacity_bytes = _g1->capacity(); 3.12 + return (double) reclaimable_bytes * 100.0 / (double) capacity_bytes; 3.13 +} 3.14 + 3.15 bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, 3.16 const char* false_action_str) { 3.17 CollectionSetChooser* cset_chooser = _collectionSetChooser; 3.18 @@ -1815,19 +1823,21 @@ 3.19 ergo_format_reason("candidate old regions not available")); 3.20 return false; 3.21 } 3.22 + 3.23 + // Is the amount of uncollected reclaimable space above G1HeapWastePercent? 3.24 size_t reclaimable_bytes = cset_chooser->remaining_reclaimable_bytes(); 3.25 - size_t capacity_bytes = _g1->capacity(); 3.26 - double perc = (double) reclaimable_bytes * 100.0 / (double) capacity_bytes; 3.27 + double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); 3.28 double threshold = (double) G1HeapWastePercent; 3.29 - if (perc < threshold) { 3.30 + if (reclaimable_perc <= threshold) { 3.31 ergo_verbose4(ErgoMixedGCs, 3.32 false_action_str, 3.33 - ergo_format_reason("reclaimable percentage lower than threshold") 3.34 + ergo_format_reason("reclaimable percentage not over threshold") 3.35 ergo_format_region("candidate old regions") 3.36 ergo_format_byte_perc("reclaimable") 3.37 ergo_format_perc("threshold"), 3.38 cset_chooser->remaining_regions(), 3.39 - reclaimable_bytes, perc, threshold); 3.40 + reclaimable_bytes, 3.41 + reclaimable_perc, threshold); 3.42 return false; 3.43 } 3.44 3.45 @@ -1838,10 +1848,50 @@ 3.46 ergo_format_byte_perc("reclaimable") 3.47 ergo_format_perc("threshold"), 3.48 cset_chooser->remaining_regions(), 3.49 - reclaimable_bytes, perc, threshold); 3.50 + reclaimable_bytes, 3.51 + reclaimable_perc, threshold); 3.52 return true; 3.53 } 3.54 3.55 +uint G1CollectorPolicy::calc_min_old_cset_length() { 3.56 + // The min old CSet region bound is based on the maximum desired 3.57 + // number of mixed GCs after a cycle. I.e., even if some old regions 3.58 + // look expensive, we should add them to the CSet anyway to make 3.59 + // sure we go through the available old regions in no more than the 3.60 + // maximum desired number of mixed GCs. 3.61 + // 3.62 + // The calculation is based on the number of marked regions we added 3.63 + // to the CSet chooser in the first place, not how many remain, so 3.64 + // that the result is the same during all mixed GCs that follow a cycle. 3.65 + 3.66 + const size_t region_num = (size_t) _collectionSetChooser->length(); 3.67 + const size_t gc_num = (size_t) MAX2(G1MixedGCCountTarget, (uintx) 1); 3.68 + size_t result = region_num / gc_num; 3.69 + // emulate ceiling 3.70 + if (result * gc_num < region_num) { 3.71 + result += 1; 3.72 + } 3.73 + return (uint) result; 3.74 +} 3.75 + 3.76 +uint G1CollectorPolicy::calc_max_old_cset_length() { 3.77 + // The max old CSet region bound is based on the threshold expressed 3.78 + // as a percentage of the heap size. I.e., it should bound the 3.79 + // number of old regions added to the CSet irrespective of how many 3.80 + // of them are available. 3.81 + 3.82 + G1CollectedHeap* g1h = G1CollectedHeap::heap(); 3.83 + const size_t region_num = g1h->n_regions(); 3.84 + const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; 3.85 + size_t result = region_num * perc / 100; 3.86 + // emulate ceiling 3.87 + if (100 * result < region_num * perc) { 3.88 + result += 1; 3.89 + } 3.90 + return (uint) result; 3.91 +} 3.92 + 3.93 + 3.94 void G1CollectorPolicy::finalize_cset(double target_pause_time_ms) { 3.95 double young_start_time_sec = os::elapsedTime(); 3.96 3.97 @@ -1855,7 +1905,7 @@ 3.98 3.99 double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); 3.100 double predicted_pause_time_ms = base_time_ms; 3.101 - double time_remaining_ms = target_pause_time_ms - base_time_ms; 3.102 + double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); 3.103 3.104 ergo_verbose4(ErgoCSetConstruction | ErgoHigh, 3.105 "start choosing CSet", 3.106 @@ -1893,7 +1943,7 @@ 3.107 3.108 _collection_set = _inc_cset_head; 3.109 _collection_set_bytes_used_before = _inc_cset_bytes_used_before; 3.110 - time_remaining_ms -= _inc_cset_predicted_elapsed_time_ms; 3.111 + time_remaining_ms = MAX2(time_remaining_ms - _inc_cset_predicted_elapsed_time_ms, 0.0); 3.112 predicted_pause_time_ms += _inc_cset_predicted_elapsed_time_ms; 3.113 3.114 ergo_verbose3(ErgoCSetConstruction | ErgoHigh, 3.115 @@ -1917,8 +1967,8 @@ 3.116 if (!gcs_are_young()) { 3.117 CollectionSetChooser* cset_chooser = _collectionSetChooser; 3.118 cset_chooser->verify(); 3.119 - const uint min_old_cset_length = cset_chooser->calc_min_old_cset_length(); 3.120 - const uint max_old_cset_length = cset_chooser->calc_max_old_cset_length(); 3.121 + const uint min_old_cset_length = calc_min_old_cset_length(); 3.122 + const uint max_old_cset_length = calc_max_old_cset_length(); 3.123 3.124 uint expensive_region_num = 0; 3.125 bool check_time_remaining = adaptive_young_list_length(); 3.126 @@ -1936,6 +1986,30 @@ 3.127 break; 3.128 } 3.129 3.130 + 3.131 + // Stop adding regions if the remaining reclaimable space is 3.132 + // not above G1HeapWastePercent. 3.133 + size_t reclaimable_bytes = cset_chooser->remaining_reclaimable_bytes(); 3.134 + double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); 3.135 + double threshold = (double) G1HeapWastePercent; 3.136 + if (reclaimable_perc <= threshold) { 3.137 + // We've added enough old regions that the amount of uncollected 3.138 + // reclaimable space is at or below the waste threshold. Stop 3.139 + // adding old regions to the CSet. 3.140 + ergo_verbose5(ErgoCSetConstruction, 3.141 + "finish adding old regions to CSet", 3.142 + ergo_format_reason("reclaimable percentage not over threshold") 3.143 + ergo_format_region("old") 3.144 + ergo_format_region("max") 3.145 + ergo_format_byte_perc("reclaimable") 3.146 + ergo_format_perc("threshold"), 3.147 + old_cset_region_length(), 3.148 + max_old_cset_length, 3.149 + reclaimable_bytes, 3.150 + reclaimable_perc, threshold); 3.151 + break; 3.152 + } 3.153 + 3.154 double predicted_time_ms = predict_region_elapsed_time_ms(hr, gcs_are_young()); 3.155 if (check_time_remaining) { 3.156 if (predicted_time_ms > time_remaining_ms) { 3.157 @@ -1975,7 +2049,7 @@ 3.158 } 3.159 3.160 // We will add this region to the CSet. 3.161 - time_remaining_ms -= predicted_time_ms; 3.162 + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); 3.163 predicted_pause_time_ms += predicted_time_ms; 3.164 cset_chooser->remove_and_move_to_next(hr); 3.165 _g1->old_set_remove(hr);
4.1 --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Mon Mar 04 13:01:24 2013 +0100 4.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Mon Mar 04 12:42:14 2013 -0800 4.3 @@ -619,6 +619,18 @@ 4.4 bool predict_will_fit(uint young_length, double base_time_ms, 4.5 uint base_free_regions, double target_pause_time_ms); 4.6 4.7 + // Calculate the minimum number of old regions we'll add to the CSet 4.8 + // during a mixed GC. 4.9 + uint calc_min_old_cset_length(); 4.10 + 4.11 + // Calculate the maximum number of old regions we'll add to the CSet 4.12 + // during a mixed GC. 4.13 + uint calc_max_old_cset_length(); 4.14 + 4.15 + // Returns the given amount of uncollected reclaimable space 4.16 + // as a percentage of the current heap capacity. 4.17 + double reclaimable_bytes_perc(size_t reclaimable_bytes); 4.18 + 4.19 public: 4.20 4.21 G1CollectorPolicy();