8007036: G1: Too many old regions added to last mixed GC

Mon, 04 Mar 2013 12:42:14 -0800

author
johnc
date
Mon, 04 Mar 2013 12:42:14 -0800
changeset 4681
27714220e50e
parent 4680
0624b9d81255
child 4682
d778bb46a9a5

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

src/share/vm/gc_implementation/g1/collectionSetChooser.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/collectionSetChooser.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp file | annotate | diff | comparison | revisions
     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();

mercurial