< prev index next >

src/share/vm/gc/g1/g1IHOPControl.cpp

Print this page
rev 9402 : dihop-changes
rev 9403 : imported patch sihop-thomas-review
rev 9404 : imported patch erik-jmasa-review
rev 9405 : imported patch 8136678-implement-adaptive-sizing-algorithm-for-IHOP
rev 9406 : imported patch aihop-thomas-review
rev 9407 : [mq]: erik-jon-review


   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "gc/g1/g1CollectedHeap.inline.hpp"
  27 #include "gc/g1/g1ErgoVerbose.hpp"
  28 #include "gc/g1/g1IHOPControl.hpp"

  29 
  30 G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) :
  31   _initial_ihop_percent(initial_ihop_percent),
  32   _target_occupancy(target_occupancy) {
  33   assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "Initial IHOP value must be between 0 and 100 but is %.3f", initial_ihop_percent);
  34 }
  35 
  36 G1StaticIHOPControl::G1StaticIHOPControl(double ihop_percent, size_t target_occupancy) :
  37   G1IHOPControl(ihop_percent, target_occupancy),
  38   _last_allocation_time_s(0.0),
  39   _last_allocated_bytes(0),
  40   _last_marking_length_s(0.0) {
  41   assert(_target_occupancy > 0, "Target occupancy must be larger than zero.");
  42 }
  43 
  44 void G1StaticIHOPControl::print() {
  45   ergo_verbose6(ErgoIHOP,
  46                 "basic information",
  47                 ergo_format_reason("value update")
  48                 ergo_format_byte_perc("threshold")
  49                 ergo_format_byte("target occupancy")
  50                 ergo_format_byte("current occupancy")
  51                 ergo_format_double("recent old gen allocation rate")
  52                 ergo_format_ms("recent marking phase length"),
  53                 get_conc_mark_start_threshold(),
  54                 _initial_ihop_percent,
  55                 _target_occupancy,
  56                 G1CollectedHeap::heap()->used(),
  57                 _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0,
  58                 _last_marking_length_s * 1000.0);
  59 }
  60 
  61 #ifndef PRODUCT
  62 static void test_update(G1IHOPControl* ctrl, double alloc_time, size_t alloc_amount, size_t young_size, double mark_time) {
  63   for (int i = 0; i < 100; i++) {
  64     ctrl->update_allocation_info(alloc_time, alloc_amount, young_size);
  65     ctrl->update_marking_length(mark_time);
  66   }
  67 }
  68 
  69 void G1StaticIHOPControl::test() {
  70   size_t const initial_ihop = 45;
  71 
  72   G1StaticIHOPControl ctrl(initial_ihop, 100);
  73   size_t threshold;
  74   
  75   threshold = ctrl.get_conc_mark_start_threshold();
  76   assert(threshold == initial_ihop,
  77          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  78 


  82          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  83 
  84   ctrl.update_marking_length(1000.0);
  85   threshold = ctrl.get_conc_mark_start_threshold();
  86   assert(threshold == initial_ihop,
  87          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  88 
  89   // Whatever we pass, the IHOP value must stay the same.
  90   test_update(&ctrl, 2, 10, 10, 3);
  91   threshold = ctrl.get_conc_mark_start_threshold();
  92   assert(threshold == initial_ihop,
  93          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  94 
  95   test_update(&ctrl, 12, 10, 10, 3);
  96   threshold = ctrl.get_conc_mark_start_threshold();
  97   assert(threshold == initial_ihop,
  98          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  99 }
 100 #endif
 101 
























































































































 102 #ifndef PRODUCT




































































 103 void IHOP_test() {
 104   G1StaticIHOPControl::test();

 105 }
 106 #endif


   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "gc/g1/g1CollectedHeap.inline.hpp"
  27 #include "gc/g1/g1ErgoVerbose.hpp"
  28 #include "gc/g1/g1IHOPControl.hpp"
  29 #include "gc/g1/g1Predictions.hpp"
  30 
  31 G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) :
  32   _initial_ihop_percent(initial_ihop_percent),
  33   _target_occupancy(target_occupancy) {
  34   assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "Initial IHOP value must be between 0 and 100 but is %.3f", initial_ihop_percent);
  35 }
  36 
  37 G1StaticIHOPControl::G1StaticIHOPControl(double ihop_percent, size_t target_occupancy) :
  38   G1IHOPControl(ihop_percent, target_occupancy),
  39   _last_allocation_time_s(0.0),
  40   _last_allocated_bytes(0),
  41   _last_marking_length_s(0.0) {
  42   assert(_target_occupancy > 0, "Target occupancy must be larger than zero.");
  43 }
  44 
  45 void G1StaticIHOPControl::print() {
  46   ergo_verbose6(ErgoIHOP,
  47                 "basic information",
  48                 ergo_format_reason("value update")
  49                 ergo_format_byte_perc("threshold")
  50                 ergo_format_byte("target occupancy")
  51                 ergo_format_byte("current occupancy")
  52                 ergo_format_double("recent old gen allocation rate")
  53                 ergo_format_double("recent marking phase length"),
  54                 get_conc_mark_start_threshold(),
  55                 _initial_ihop_percent,
  56                 _target_occupancy,
  57                 G1CollectedHeap::heap()->used(),
  58                 _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0,
  59                 _last_marking_length_s);
  60 }
  61 
  62 #ifndef PRODUCT
  63 static void test_update(G1IHOPControl* ctrl, double alloc_time, size_t alloc_amount, size_t young_size, double mark_time) {
  64   for (int i = 0; i < 100; i++) {
  65     ctrl->update_allocation_info(alloc_time, alloc_amount, young_size);
  66     ctrl->update_marking_length(mark_time);
  67   }
  68 }
  69 
  70 void G1StaticIHOPControl::test() {
  71   size_t const initial_ihop = 45;
  72 
  73   G1StaticIHOPControl ctrl(initial_ihop, 100);
  74   size_t threshold;
  75   
  76   threshold = ctrl.get_conc_mark_start_threshold();
  77   assert(threshold == initial_ihop,
  78          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  79 


  83          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  84 
  85   ctrl.update_marking_length(1000.0);
  86   threshold = ctrl.get_conc_mark_start_threshold();
  87   assert(threshold == initial_ihop,
  88          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  89 
  90   // Whatever we pass, the IHOP value must stay the same.
  91   test_update(&ctrl, 2, 10, 10, 3);
  92   threshold = ctrl.get_conc_mark_start_threshold();
  93   assert(threshold == initial_ihop,
  94          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
  95 
  96   test_update(&ctrl, 12, 10, 10, 3);
  97   threshold = ctrl.get_conc_mark_start_threshold();
  98   assert(threshold == initial_ihop,
  99          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
 100 }
 101 #endif
 102 
 103 G1AdaptiveIHOPControl::G1AdaptiveIHOPControl(double ihop_percent,
 104                                              size_t initial_target_occupancy,
 105                                              G1Predictions const* predictor,
 106                                              size_t heap_reserve_percent,
 107                                              size_t heap_waste_percent) :
 108   G1IHOPControl(ihop_percent, initial_target_occupancy),
 109   _predictor(predictor),
 110   _marking_times_s(10, 0.95),
 111   _allocation_rate_s(10, 0.95),
 112   _last_unrestrained_young_size(0),
 113   _current_threshold(0.0),
 114   _heap_reserve_percent(heap_reserve_percent),
 115   _heap_waste_percent(heap_waste_percent)
 116 {
 117   calculate();
 118 }
 119 
 120 void G1AdaptiveIHOPControl::calculate() {
 121   if (have_enough_data_for_prediction()) {
 122     double pred_marking_time = _predictor->get_new_prediction(&_marking_times_s);
 123     double pred_promotion_rate = _predictor->get_new_prediction(&_allocation_rate_s);
 124 
 125     size_t predicted_needed_bytes_during_marking =
 126       (pred_marking_time * pred_promotion_rate +
 127       _last_unrestrained_young_size); // In reality we would need the maximum size of the young gen during marking. This is a conservative estimate.
 128 
 129     size_t internal_threshold = actual_target_threshold();
 130     size_t predicted_initiating_threshold = predicted_needed_bytes_during_marking < internal_threshold ?
 131                                             internal_threshold - predicted_needed_bytes_during_marking :
 132                                             0;
 133     _current_threshold = predicted_initiating_threshold;
 134   } else {
 135     // Use the initial value.
 136     _current_threshold = _initial_ihop_percent * _target_occupancy / 100.0;  
 137   }
 138 }
 139 
 140 size_t G1AdaptiveIHOPControl::actual_target_threshold() const {
 141   // The actual target threshold takes the heap reserve and the expected waste in
 142   // free space  into account.
 143   // _heap_reserve is that part of the total heap capacity that is reserved for
 144   // eventual promotion failure.
 145   // _heap_waste is the amount of space will never be reclaimed in any
 146   // heap, so can not be used for allocation during marking and must always be
 147   // considered.
 148 
 149   double safe_total_heap_percentage = MIN2((double)(_heap_reserve_percent + _heap_waste_percent), 100.0);
 150 
 151   return MIN2(
 152     G1CollectedHeap::heap()->max_capacity() * (100.0 - safe_total_heap_percentage) / 100.0,
 153     _target_occupancy * (100.0 - _heap_waste_percent) / 100.0
 154     );
 155 }
 156 
 157 bool G1AdaptiveIHOPControl::have_enough_data_for_prediction() const {
 158   return ((size_t)_marking_times_s.num() >= G1AdaptiveIHOPNumInitialSamples) &&
 159          ((size_t)_allocation_rate_s.num() >= G1AdaptiveIHOPNumInitialSamples);
 160 }
 161 
 162 void G1AdaptiveIHOPControl::set_target_occupancy(size_t target_occupancy) {
 163   _target_occupancy = target_occupancy;
 164 }
 165 
 166 size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() {
 167   calculate();
 168   return _current_threshold;
 169 }
 170 
 171 void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size) {
 172   assert(allocation_time_s >= 0.0, "Allocation time must be positive but is %.3f", allocation_time_s);
 173   double allocation_rate = (double) allocated_bytes / allocation_time_s;
 174   _allocation_rate_s.add(allocation_rate);
 175 
 176   _last_allocation_bytes = allocated_bytes;
 177   _last_unrestrained_young_size = additional_buffer_size;
 178 }
 179 
 180 void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) {
 181    assert(marking_length_s >= 0.0, "Marking length must be larger than zero but is %.3f", marking_length_s);
 182   _marking_times_s.add(marking_length_s);
 183 }
 184 
 185 static double percentage_of(double quantity, double base_quantity) {
 186   return base_quantity > 0.0 ? (quantity / base_quantity) * 100.0 : 0.0;
 187 }
 188 
 189 void G1AdaptiveIHOPControl::print() {
 190   ergo_verbose6(ErgoIHOP,
 191                 "basic information",
 192                 ergo_format_reason("value update")
 193                 ergo_format_byte_perc("threshold")
 194                 ergo_format_byte("target occupancy")
 195                 ergo_format_byte("current occupancy")
 196                 ergo_format_double("recent old gen allocation rate")
 197                 ergo_format_double("recent marking phase length"),
 198                 get_conc_mark_start_threshold(),
 199                 percentage_of(get_conc_mark_start_threshold(), _target_occupancy),
 200                 _target_occupancy,
 201                 G1CollectedHeap::heap()->used(),
 202                 _allocation_rate_s.last(),
 203                 _marking_times_s.last()
 204                 );
 205   size_t actual_target = actual_target_threshold();
 206   ergo_verbose6(ErgoIHOP, 
 207                 "adaptive IHOP information",
 208                 ergo_format_reason("value update")
 209                 ergo_format_byte_perc("threshold")
 210                 ergo_format_byte("internal target occupancy")
 211                 ergo_format_double("predicted old gen allocation rate")
 212                 ergo_format_double("predicted marking phase length")
 213                 ergo_format_str("prediction active"),
 214                 get_conc_mark_start_threshold(),
 215                 percentage_of(get_conc_mark_start_threshold(), actual_target),
 216                 actual_target,
 217                 _predictor->get_new_prediction(&_allocation_rate_s),
 218                 _predictor->get_new_prediction(&_marking_times_s),
 219                 have_enough_data_for_prediction() ? "true" : "false"
 220                 );
 221 }
 222 
 223 #ifndef PRODUCT
 224 void G1AdaptiveIHOPControl::test() {
 225   size_t const initial_threshold = 45;
 226   size_t const young_size = 10;
 227   size_t const target_size = 100;
 228 
 229   // The final IHOP value is always
 230   // target_size - (young_size + alloc_amount/alloc_time * marking_time)
 231 
 232   G1Predictions pred(0.95);
 233   G1AdaptiveIHOPControl ctrl(initial_threshold, target_size, &pred, 0, 0);
 234 
 235   // First "load".
 236   size_t const alloc_time1 = 2;
 237   size_t const alloc_amount1 = 10;
 238   size_t const marking_time1 = 2;
 239   size_t const settled_ihop1 = target_size - (young_size + alloc_amount1/alloc_time1 * marking_time1);
 240 
 241   size_t threshold;
 242   threshold = ctrl.get_conc_mark_start_threshold();
 243   assert(threshold == initial_threshold,
 244          "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_threshold, threshold);
 245   for (size_t i = 0; i < G1AdaptiveIHOPNumInitialSamples - 1; i++) {
 246     ctrl.update_allocation_info(alloc_time1, alloc_amount1, young_size);
 247     ctrl.update_marking_length(marking_time1);
 248     // Not enough data yet.
 249     threshold = ctrl.get_conc_mark_start_threshold();
 250     assert(threshold == initial_threshold,
 251            "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_threshold, threshold);
 252   }
 253  
 254   test_update(&ctrl, alloc_time1, alloc_amount1, young_size, marking_time1);
 255   
 256   threshold = ctrl.get_conc_mark_start_threshold();
 257   assert(threshold == settled_ihop1,
 258          "Expected IHOP threshold to settle at " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop1, threshold);
 259 
 260   // Second "load". A bit higher allocation rate.
 261   size_t const alloc_time2 = 2;
 262   size_t const alloc_amount2 = 30;
 263   size_t const marking_time2 = 2;
 264   size_t const settled_ihop2 = target_size - (young_size + alloc_amount2/alloc_time2 * marking_time2);
 265 
 266   test_update(&ctrl, alloc_time2, alloc_amount2, young_size, marking_time2);
 267 
 268   threshold = ctrl.get_conc_mark_start_threshold();
 269   assert(threshold < settled_ihop1,
 270          "Expected IHOP threshold to settle at a value lower than " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop1, threshold);
 271 
 272   // Third "load". Very high (impossible) allocation rate.
 273   size_t const alloc_time3 = 1;
 274   size_t const alloc_amount3 = 50;
 275   size_t const marking_time3 = 2;
 276   size_t const settled_ihop3 = 0;
 277 
 278   test_update(&ctrl, alloc_time3, alloc_amount3, young_size, marking_time3);
 279   threshold = ctrl.get_conc_mark_start_threshold();
 280 
 281   assert(threshold == settled_ihop3,
 282          "Expected IHOP threshold to settle at " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop3, threshold);
 283 
 284   // And back to some arbitrary value.
 285   test_update(&ctrl, alloc_time2, alloc_amount2, young_size, marking_time2);
 286 
 287   threshold = ctrl.get_conc_mark_start_threshold();
 288   assert(threshold > settled_ihop3,
 289          "Expected IHOP threshold to settle at value larger than " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop3, threshold);
 290 }
 291 
 292 void IHOP_test() {
 293   G1StaticIHOPControl::test();
 294   G1AdaptiveIHOPControl::test();  
 295 }
 296 #endif
< prev index next >