< prev index next >

src/share/vm/gc/shenandoah/shenandoahCollectorPolicy.cpp

Print this page




  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "gc/shared/gcPolicyCounters.hpp"
  25 #include "gc/shenandoah/shenandoahCollectionSet.hpp"
  26 #include "gc/shenandoah/shenandoahFreeSet.hpp"
  27 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
  28 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  29 #include "gc/shenandoah/shenandoahPhaseTimes.hpp"
  30 
  31 int compareHeapRegionsByGarbage(ShenandoahHeapRegion* a, ShenandoahHeapRegion* b) {
  32   if (a == NULL) {
  33     if (b == NULL) {
  34       return 0;
  35     } else {
  36       return 1;
  37     }
  38   } else if (b == NULL) {
  39     return -1;
  40   }
  41 
  42   size_t garbage_a = a->garbage();
  43   size_t garbage_b = b->garbage();
  44 
  45   if (garbage_a > garbage_b)
  46     return -1;
  47   else if (garbage_a < garbage_b)
  48     return 1;
  49   else return 0;
  50 }
  51 
  52 class ShenandoahHeuristics : public CHeapObj<mtGC> {
  53 
  54   NumberSeq _allocation_rate_bytes;
  55   NumberSeq _reclamation_rate_bytes;
  56 
  57   size_t _bytes_allocated_since_CM;
  58   size_t _bytes_reclaimed_this_cycle;
  59 
  60 protected:
  61   size_t _bytes_allocated_start_CM;
  62   size_t _bytes_allocated_during_CM;
  63 
  64 private:
  65   size_t _garbage_threshold;
  66 
  67 public:
  68 
  69   ShenandoahHeuristics();
  70 
  71   void record_bytes_allocated(size_t bytes);
  72   void record_bytes_reclaimed(size_t bytes);
  73   void record_bytes_start_CM(size_t bytes);
  74   void record_bytes_end_CM(size_t bytes);
  75 
  76   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const=0;
  77 
  78   virtual void choose_collection_set(ShenandoahCollectionSet* collection_set);
  79   virtual void choose_collection_set_min_garbage(ShenandoahCollectionSet* collection_set, size_t min_garbage);






  80   virtual void choose_free_set(ShenandoahFreeSet* free_set);
  81 
  82   virtual bool process_references() {
  83     if (ShenandoahRefProcFrequency == 0) return false;
  84     size_t cycle = ShenandoahHeap::heap()->shenandoahPolicy()->cycle_counter();
  85     // Process references every Nth GC cycle.
  86     return cycle % ShenandoahRefProcFrequency == 0;
  87   }
  88 
  89   virtual bool unload_classes() {
  90     if (ShenandoahUnloadClassesFrequency == 0) return false;
  91     size_t cycle = ShenandoahHeap::heap()->shenandoahPolicy()->cycle_counter();
  92     // Process references every Nth GC cycle.
  93     return cycle % ShenandoahUnloadClassesFrequency == 0;
  94   }
  95 
  96 protected:
  97 
  98   void set_garbage_threshold(size_t threshold) {
  99     _garbage_threshold = threshold;
 100   }
 101 
 102   size_t garbage_threshold() {
 103     return _garbage_threshold;
 104   }
 105 };
 106 
 107 ShenandoahHeuristics::ShenandoahHeuristics() :
 108   _bytes_allocated_since_CM(0),
 109   _bytes_reclaimed_this_cycle(0),
 110   _bytes_allocated_start_CM(0),
 111   _bytes_allocated_during_CM(0),
 112   _garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes / 2)
 113 {
 114 }
 115 





















 116 void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) {
 117   ShenandoahHeapRegionSet* sorted_regions = ShenandoahHeap::heap()->sorted_regions();
 118   sorted_regions->sort(compareHeapRegionsByGarbage);
 119 


 120   size_t i = 0;
 121   size_t end = sorted_regions->active_regions();
 122   ShenandoahHeap* heap = ShenandoahHeap::heap();
 123   while (i < end) {
 124     ShenandoahHeapRegion* region = sorted_regions->get(i++);
 125     if (region->garbage() > _garbage_threshold && ! region->is_humongous() && ! region->is_pinned()) {
 126       log_develop_trace(gc)("Choose region " SIZE_FORMAT " with garbage = " SIZE_FORMAT
 127                             " and live = " SIZE_FORMAT " and _garbage_threshold = " SIZE_FORMAT "\n",
 128                             region->region_number(), region->garbage(), region->get_live_data(), _garbage_threshold);
 129 
 130       assert(! region->is_humongous(), "no humongous regions in collection set");
 131 
 132       if (region->get_live_data() == 0) {

 133         // We can recycle it right away and put it in the free set.


 134         heap->decrease_used(region->used());
 135         region->recycle();
 136       } else {






 137         collection_set->add_region(region);
 138         region->set_in_collection_set(true);
 139       }
 140     } else {

 141       log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT
 142                             " and live = " SIZE_FORMAT " and _garbage_threshold = " SIZE_FORMAT "\n",
 143                             region->region_number(), region->garbage(), region->get_live_data(), _garbage_threshold);
 144     }
 145   }
 146 
 147 }
 148 
 149 void ShenandoahHeuristics::choose_collection_set_min_garbage(ShenandoahCollectionSet* collection_set, size_t min_garbage) {
 150   ShenandoahHeapRegionSet* sorted_regions = ShenandoahHeap::heap()->sorted_regions();
 151   sorted_regions->sort(compareHeapRegionsByGarbage);
 152   size_t i = 0;
 153   size_t end = sorted_regions->active_regions();
 154 
 155   size_t garbage = 0;
 156   while (i < end && garbage < min_garbage) {
 157     ShenandoahHeapRegion* region = sorted_regions->get(i++);
 158     if (region->garbage() > _garbage_threshold && ! region->is_humongous() && ! region->is_pinned()) {
 159       collection_set->add_region(region);
 160       garbage += region->garbage();
 161       region->set_in_collection_set(true);
 162     }
 163   }
 164 }
 165 
 166 void ShenandoahHeuristics::choose_free_set(ShenandoahFreeSet* free_set) {
 167 
 168   ShenandoahHeapRegionSet* ordered_regions = ShenandoahHeap::heap()->regions();
 169   size_t i = 0;
 170   size_t end = ordered_regions->active_regions();
 171 
 172   ShenandoahHeap* heap = ShenandoahHeap::heap();
 173   while (i < end) {
 174     ShenandoahHeapRegion* region = ordered_regions->get(i++);
 175     if ((! heap->in_collection_set(region))
 176         && (! region->is_humongous())
 177         && (! region->is_pinned())) {
 178       free_set->add_region(region);
 179     }
 180   }
 181 }
 182 
 183 void ShenandoahCollectorPolicy::record_workers_start(TimingPhase phase) {


 216   _allocation_rate_bytes.add(bytes);
 217 }
 218 
 219 void ShenandoahHeuristics::record_bytes_reclaimed(size_t bytes) {
 220   _bytes_reclaimed_this_cycle = bytes;
 221   _reclamation_rate_bytes.add(bytes);
 222 }
 223 
 224 void ShenandoahHeuristics::record_bytes_start_CM(size_t bytes) {
 225   _bytes_allocated_start_CM = bytes;
 226 }
 227 
 228 void ShenandoahHeuristics::record_bytes_end_CM(size_t bytes) {
 229   _bytes_allocated_during_CM = (bytes > _bytes_allocated_start_CM) ? (bytes - _bytes_allocated_start_CM)
 230                                                                    : bytes;
 231 }
 232 
 233 class PassiveHeuristics : public ShenandoahHeuristics {
 234 public:
 235   PassiveHeuristics() : ShenandoahHeuristics() {
 236     set_garbage_threshold(8);



 237   }
 238 
 239   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 240     // Never do concurrent GCs.
 241     return false;
 242   }
 243 
 244   virtual bool process_references() {
 245     // Randomly process refs with 50% chance.
 246     return (os::random() & 1) == 1;
 247   }
 248 
 249   virtual bool unload_classes() {
 250     // Randomly unload classes with 50% chance.
 251     return (os::random() & 1) == 1;
 252   }
 253 };
 254 
 255 class AggressiveHeuristics : public ShenandoahHeuristics {
 256 public:
 257   AggressiveHeuristics() : ShenandoahHeuristics() {
 258     set_garbage_threshold(8);



 259   }
 260 
 261   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 262     return true;
 263   }
 264 
 265   virtual bool process_references() {
 266     // Randomly process refs with 50% chance.
 267     return (os::random() & 1) == 1;
 268   }
 269 
 270   virtual bool unload_classes() {
 271     // Randomly unload classes with 50% chance.
 272     return (os::random() & 1) == 1;
 273   }
 274 };
 275 
 276 class DynamicHeuristics : public ShenandoahHeuristics {
 277 public:
 278   DynamicHeuristics() : ShenandoahHeuristics() {
 279     log_info(gc, init)("Shenandoah dynamic heuristics thresholds: allocation "SIZE_FORMAT", free "SIZE_FORMAT", garbage "SIZE_FORMAT,
 280                        ShenandoahAllocationThreshold,
 281                        ShenandoahFreeThreshold,
 282                        ShenandoahGarbageThreshold);
 283   }
 284 
 285   virtual ~DynamicHeuristics() {}
 286 
 287   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 288 
 289     bool shouldStartConcurrentMark = false;
 290 
 291     ShenandoahHeap* heap = ShenandoahHeap::heap();
 292     size_t free_capacity = heap->free_regions()->capacity();
 293     size_t free_used = heap->free_regions()->used();
 294     assert(free_used <= free_capacity, "must use less than capacity");
 295     size_t available =  free_capacity - free_used;
 296     uintx factor = heap->need_update_refs() ? ShenandoahFreeThreshold : ShenandoahInitialFreeThreshold;
 297     size_t targetStartMarking = (capacity * factor) / 100;
 298 
 299     size_t threshold_bytes_allocated = heap->capacity() * ShenandoahAllocationThreshold / 100;
 300     if (available < targetStartMarking &&
 301         heap->bytes_allocated_since_cm() > threshold_bytes_allocated)
 302     {
 303       // Need to check that an appropriate number of regions have
 304       // been allocated since last concurrent mark too.
 305       shouldStartConcurrentMark = true;
 306     }
 307 
 308     return shouldStartConcurrentMark;
 309   }
 310 
 311   virtual void choose_collection_set(ShenandoahCollectionSet* collection_set) {
 312     set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100);
 313     ShenandoahHeuristics::choose_collection_set(collection_set);
 314   }

 315 };
 316 
 317 
 318 class AdaptiveHeuristics : public ShenandoahHeuristics {
 319 private:
 320   size_t _max_live_data;
 321   double _used_threshold_factor;
 322   double _garbage_threshold_factor;
 323   double _allocation_threshold_factor;
 324 
 325   uintx _used_threshold;
 326   uintx _garbage_threshold;
 327   uintx _allocation_threshold;
 328 

 329 public:
 330   AdaptiveHeuristics() : ShenandoahHeuristics() {
 331     _max_live_data = 0;
 332 
 333     _used_threshold = 0;
 334     _garbage_threshold = 0;
 335     _allocation_threshold = 0;
 336 
 337     _used_threshold_factor = 0.;
 338     _garbage_threshold_factor = 0.1;
 339     _allocation_threshold_factor = 0.;
 340   }
 341 
 342   virtual ~AdaptiveHeuristics() {}
 343 
















 344   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 345 
 346     ShenandoahHeap* _heap = ShenandoahHeap::heap();
 347     bool shouldStartConcurrentMark = false;
 348     OrderAccess::release();
 349 
 350     size_t max_live_data = _max_live_data;
 351     if (max_live_data == 0) {
 352       max_live_data = capacity * 0.2; // Very generous initial value.
 353     } else {
 354       max_live_data *= 1.3; // Add some wiggle room.
 355     }
 356     size_t max_cycle_allocated = _heap->max_allocated_gc();
 357     if (max_cycle_allocated == 0) {
 358       max_cycle_allocated = capacity * 0.3; // Very generous.
 359     } else {
 360       max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough.
 361     }
 362     size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data;
 363     if (used > threshold)
 364     {
 365       shouldStartConcurrentMark = true;
 366     }
 367 
 368     return shouldStartConcurrentMark;
 369   }
 370 
 371   virtual void choose_collection_set(ShenandoahCollectionSet* collection_set) {
 372     size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm();
 373     size_t min_garbage =  bytes_alloc/* * 1.1*/;
 374     set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100);
 375     ShenandoahHeuristics::choose_collection_set_min_garbage(collection_set, min_garbage);








 376 
 377     log_develop_trace(gc)("Garbage to be collected: "SIZE_FORMAT, collection_set->garbage());
 378     log_develop_trace(gc)("Objects to be evacuated: "SIZE_FORMAT, collection_set->live_data());












 379 
 380     _max_live_data = MAX2(_max_live_data, collection_set->live_data());



























 381   }
 382 };
 383 
 384 ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() : _cycle_counter(0) {
 385 
 386   ShenandoahHeapRegion::setup_heap_region_size(initial_heap_byte_size(), max_heap_byte_size());
 387 
 388   initialize_all();
 389 
 390   _tracer = new (ResourceObj::C_HEAP, mtGC) ShenandoahTracer();
 391   _stw_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
 392   _conc_timer = new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer();
 393   _user_requested_gcs = 0;
 394   _allocation_failure_gcs = 0;
 395   _conc_gc_aborted = false;
 396 
 397   _phase_names[init_mark] = "Initial Mark Pauses (net)";
 398   _phase_names[init_mark_gross] = "Initial Mark Pauses (gross)";
 399   _phase_names[final_mark] = "Final Mark Pauses (net)";
 400   _phase_names[final_mark_gross] = "Final Mark Pauses (gross)";


 454 
 455   _phase_names[full_gc] = "Full GC Times";
 456   _phase_names[full_gc_mark] = "  Mark";
 457   _phase_names[full_gc_mark_drain_queues] = "    Drain Queues";
 458   _phase_names[full_gc_mark_weakrefs] = "    Weak References";
 459   _phase_names[full_gc_mark_class_unloading] = "    Class Unloading";
 460   _phase_names[full_gc_calculate_addresses] = "  Calculate Addresses";
 461   _phase_names[full_gc_adjust_pointers] = "  Adjust Pointers";
 462   _phase_names[full_gc_copy_objects] = "  Copy Objects";
 463 
 464   _phase_names[conc_mark] = "Concurrent Marking Times";
 465   _phase_names[conc_evac] = "Concurrent Evacuation Times";
 466 
 467   if (ShenandoahGCHeuristics != NULL) {
 468     if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) {
 469       log_info(gc, init)("Shenandoah heuristics: aggressive");
 470       _heuristics = new AggressiveHeuristics();
 471     } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) {
 472       log_info(gc, init)("Shenandoah heuristics: dynamic");
 473       _heuristics = new DynamicHeuristics();






 474     } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) {
 475       log_info(gc, init)("Shenandoah heuristics: adaptive");
 476       _heuristics = new AdaptiveHeuristics();
 477     } else if (strcmp(ShenandoahGCHeuristics, "passive") == 0) {
 478       log_info(gc, init)("Shenandoah heuristics: passive");
 479       _heuristics = new PassiveHeuristics();
 480     } else {
 481       vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option");
 482     }
 483   } else {
 484       ShouldNotReachHere();
 485   }
 486   _phase_times = new ShenandoahPhaseTimes(MAX2(ConcGCThreads, ParallelGCThreads));
 487 }
 488 
 489 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() {
 490   return this;
 491 }
 492 
 493 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() {




  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "gc/shared/gcPolicyCounters.hpp"
  25 #include "gc/shenandoah/shenandoahCollectionSet.hpp"
  26 #include "gc/shenandoah/shenandoahFreeSet.hpp"
  27 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
  28 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  29 #include "gc/shenandoah/shenandoahPhaseTimes.hpp"
  30 





















  31 class ShenandoahHeuristics : public CHeapObj<mtGC> {
  32 
  33   NumberSeq _allocation_rate_bytes;
  34   NumberSeq _reclamation_rate_bytes;
  35 
  36   size_t _bytes_allocated_since_CM;
  37   size_t _bytes_reclaimed_this_cycle;
  38 
  39 protected:
  40   size_t _bytes_allocated_start_CM;
  41   size_t _bytes_allocated_during_CM;
  42 



  43 public:
  44 
  45   ShenandoahHeuristics();
  46 
  47   void record_bytes_allocated(size_t bytes);
  48   void record_bytes_reclaimed(size_t bytes);
  49   void record_bytes_start_CM(size_t bytes);
  50   void record_bytes_end_CM(size_t bytes);
  51 
  52   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const=0;
  53 
  54   virtual void start_choose_collection_set() {
  55   }
  56   virtual void end_choose_collection_set() {
  57   }
  58   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) = 0;
  59 
  60   void choose_collection_set(ShenandoahCollectionSet* collection_set);
  61 
  62   virtual void choose_free_set(ShenandoahFreeSet* free_set);
  63 
  64   virtual bool process_references() {
  65     if (ShenandoahRefProcFrequency == 0) return false;
  66     size_t cycle = ShenandoahHeap::heap()->shenandoahPolicy()->cycle_counter();
  67     // Process references every Nth GC cycle.
  68     return cycle % ShenandoahRefProcFrequency == 0;
  69   }
  70 
  71   virtual bool unload_classes() {
  72     if (ShenandoahUnloadClassesFrequency == 0) return false;
  73     size_t cycle = ShenandoahHeap::heap()->shenandoahPolicy()->cycle_counter();
  74     // Process references every Nth GC cycle.
  75     return cycle % ShenandoahUnloadClassesFrequency == 0;
  76   }
  77 
  78 private:
  79   static int compareHeapRegionsByGarbage(ShenandoahHeapRegion* a, ShenandoahHeapRegion* b);



  80 



  81 };
  82 
  83 ShenandoahHeuristics::ShenandoahHeuristics() :
  84   _bytes_allocated_since_CM(0),
  85   _bytes_reclaimed_this_cycle(0),
  86   _bytes_allocated_start_CM(0),
  87   _bytes_allocated_during_CM(0)

  88 {
  89 }
  90 
  91 int ShenandoahHeuristics::compareHeapRegionsByGarbage(ShenandoahHeapRegion* a, ShenandoahHeapRegion* b) {
  92   if (a == NULL) {
  93     if (b == NULL) {
  94       return 0;
  95     } else {
  96       return 1;
  97     }
  98   } else if (b == NULL) {
  99     return -1;
 100   }
 101 
 102   size_t garbage_a = a->garbage();
 103   size_t garbage_b = b->garbage();
 104 
 105   if (garbage_a > garbage_b)
 106     return -1;
 107   else if (garbage_a < garbage_b)
 108     return 1;
 109   else return 0;
 110 }
 111 
 112 void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) {
 113   ShenandoahHeapRegionSet* sorted_regions = ShenandoahHeap::heap()->sorted_regions();
 114   sorted_regions->sort(compareHeapRegionsByGarbage);
 115 
 116   start_choose_collection_set();
 117 
 118   size_t i = 0;
 119   size_t end = sorted_regions->active_regions();
 120   ShenandoahHeap* heap = ShenandoahHeap::heap();
 121   size_t total_garbage = heap->garbage();
 122   size_t immediate_garbage = 0;
 123   size_t immediate_regions = 0;
 124   for (size_t i = 0; i < end; i++) {
 125     ShenandoahHeapRegion* region = sorted_regions->get(i);



 126     
 127     if (! region->is_humongous() && ! region->is_pinned()) {
 128       if ((! region->is_empty()) && region->get_live_data() == 0) {
 129         // We can recycle it right away and put it in the free set.
 130         immediate_regions++;
 131         immediate_garbage += region->garbage();
 132         heap->decrease_used(region->used());
 133         region->recycle();
 134         log_develop_trace(gc)("Choose region for immediate" SIZE_FORMAT " with garbage = " SIZE_FORMAT
 135                               " and live = " SIZE_FORMAT "\n",
 136                               region->region_number(), region->garbage(), region->get_live_data());
 137       } else if (region_in_collection_set(region, immediate_garbage)) {
 138         log_develop_trace(gc)("Choose region " SIZE_FORMAT " with garbage = " SIZE_FORMAT
 139                               " and live = " SIZE_FORMAT "\n",
 140                               region->region_number(), region->garbage(), region->get_live_data());
 141         collection_set->add_region(region);
 142         region->set_in_collection_set(true);
 143       }
 144     } else {
 145       assert(region->get_live_data() != 0 || region->is_empty() || region->is_pinned() || region->is_humongous(), "check rejected");
 146       log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT
 147                             " and live = " SIZE_FORMAT "\n",
 148                             region->region_number(), region->garbage(), region->get_live_data());
 149     }
 150   }
 151 
 152   end_choose_collection_set();






 153 
 154   log_debug(gc)("Total Garbage: "SIZE_FORMAT, total_garbage);
 155   log_debug(gc)("Immediate Garbage: "SIZE_FORMAT, immediate_garbage);
 156   log_debug(gc)("Immediate Garbage regions: "SIZE_FORMAT, immediate_regions);
 157   log_debug(gc)("Garbage to be collected: "SIZE_FORMAT, collection_set->garbage());
 158   log_debug(gc)("Objects to be evacuated: "SIZE_FORMAT, collection_set->live_data());
 159   log_debug(gc)("Live / Garbage ratio: "SIZE_FORMAT"%%", collection_set->live_data() * 100 / MAX2(collection_set->garbage(), 1UL));
 160   log_debug(gc)("Collected-Garbage ratio / Total-garbage: "SIZE_FORMAT"%%", collection_set->garbage() * 100 / MAX2(total_garbage, 1UL));


 161 }
 162 
 163 void ShenandoahHeuristics::choose_free_set(ShenandoahFreeSet* free_set) {
 164 
 165   ShenandoahHeapRegionSet* ordered_regions = ShenandoahHeap::heap()->regions();
 166   size_t i = 0;
 167   size_t end = ordered_regions->active_regions();
 168 
 169   ShenandoahHeap* heap = ShenandoahHeap::heap();
 170   while (i < end) {
 171     ShenandoahHeapRegion* region = ordered_regions->get(i++);
 172     if ((! heap->in_collection_set(region))
 173         && (! region->is_humongous())
 174         && (! region->is_pinned())) {
 175       free_set->add_region(region);
 176     }
 177   }
 178 }
 179 
 180 void ShenandoahCollectorPolicy::record_workers_start(TimingPhase phase) {


 213   _allocation_rate_bytes.add(bytes);
 214 }
 215 
 216 void ShenandoahHeuristics::record_bytes_reclaimed(size_t bytes) {
 217   _bytes_reclaimed_this_cycle = bytes;
 218   _reclamation_rate_bytes.add(bytes);
 219 }
 220 
 221 void ShenandoahHeuristics::record_bytes_start_CM(size_t bytes) {
 222   _bytes_allocated_start_CM = bytes;
 223 }
 224 
 225 void ShenandoahHeuristics::record_bytes_end_CM(size_t bytes) {
 226   _bytes_allocated_during_CM = (bytes > _bytes_allocated_start_CM) ? (bytes - _bytes_allocated_start_CM)
 227                                                                    : bytes;
 228 }
 229 
 230 class PassiveHeuristics : public ShenandoahHeuristics {
 231 public:
 232   PassiveHeuristics() : ShenandoahHeuristics() {
 233   }
 234 
 235   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) {
 236     return r->garbage() > 0;
 237   }
 238 
 239   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 240     // Never do concurrent GCs.
 241     return false;
 242   }
 243 
 244   virtual bool process_references() {
 245     // Randomly process refs with 50% chance.
 246     return (os::random() & 1) == 1;
 247   }
 248 
 249   virtual bool unload_classes() {
 250     // Randomly unload classes with 50% chance.
 251     return (os::random() & 1) == 1;
 252   }
 253 };
 254 
 255 class AggressiveHeuristics : public ShenandoahHeuristics {
 256 public:
 257   AggressiveHeuristics() : ShenandoahHeuristics() {
 258   }
 259 
 260   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) {
 261     return r->garbage() > 0;
 262   }
 263 
 264   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 265     return true;
 266   }
 267 
 268   virtual bool process_references() {
 269     // Randomly process refs with 50% chance.
 270     return (os::random() & 1) == 1;
 271   }
 272 
 273   virtual bool unload_classes() {
 274     // Randomly unload classes with 50% chance.
 275     return (os::random() & 1) == 1;
 276   }
 277 };
 278 
 279 class DynamicHeuristics : public ShenandoahHeuristics {
 280 public:
 281   DynamicHeuristics() : ShenandoahHeuristics() {
 282     log_info(gc, init)("Shenandoah heuristics thresholds: allocation "SIZE_FORMAT", free "SIZE_FORMAT", garbage "SIZE_FORMAT,
 283                        ShenandoahAllocationThreshold,
 284                        ShenandoahFreeThreshold,
 285                        ShenandoahGarbageThreshold);
 286   }
 287 
 288   virtual ~DynamicHeuristics() {}
 289 
 290   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 291 
 292     bool shouldStartConcurrentMark = false;
 293 
 294     ShenandoahHeap* heap = ShenandoahHeap::heap();
 295     size_t free_capacity = heap->free_regions()->capacity();
 296     size_t free_used = heap->free_regions()->used();
 297     assert(free_used <= free_capacity, "must use less than capacity");
 298     size_t available =  free_capacity - free_used;
 299     uintx factor = heap->need_update_refs() ? ShenandoahFreeThreshold : ShenandoahInitialFreeThreshold;
 300     size_t targetStartMarking = (capacity * factor) / 100;
 301 
 302     size_t threshold_bytes_allocated = heap->capacity() * ShenandoahAllocationThreshold / 100;
 303     if (available < targetStartMarking &&
 304         heap->bytes_allocated_since_cm() > threshold_bytes_allocated)
 305     {
 306       // Need to check that an appropriate number of regions have
 307       // been allocated since last concurrent mark too.
 308       shouldStartConcurrentMark = true;
 309     }
 310 
 311     return shouldStartConcurrentMark;
 312   }
 313 
 314   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) {
 315     size_t threshold = ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100;
 316     return r->garbage() > threshold;
 317   }
 318 
 319 };
 320 
 321 
 322 class AdaptiveHeuristics : public ShenandoahHeuristics {
 323 private:
 324   size_t _max_live_data;
 325   double _used_threshold_factor;
 326   double _garbage_threshold_factor;
 327   double _allocation_threshold_factor;
 328 
 329   uintx _used_threshold;
 330   uintx _garbage_threshold;
 331   uintx _allocation_threshold;
 332 
 333   size_t _garbage;
 334 public:
 335   AdaptiveHeuristics() : ShenandoahHeuristics() {
 336     _max_live_data = 0;
 337 
 338     _used_threshold = 0;
 339     _garbage_threshold = 0;
 340     _allocation_threshold = 0;
 341 
 342     _used_threshold_factor = 0.;
 343     _garbage_threshold_factor = 0.1;
 344     _allocation_threshold_factor = 0.;
 345   }
 346 
 347   virtual ~AdaptiveHeuristics() {}
 348 
 349   virtual void start_choose_collection_set() {
 350     _garbage = 0;
 351   }
 352 
 353   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) {
 354     size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm();
 355     size_t min_garbage =  bytes_alloc/* * 1.1*/;
 356     size_t threshold = ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100;
 357     if (_garbage < min_garbage && r->garbage() > threshold) {
 358       _garbage += r->garbage();
 359       return true;
 360     } else {
 361       return false;
 362     }
 363   }
 364 
 365   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 366 
 367     ShenandoahHeap* _heap = ShenandoahHeap::heap();
 368     bool shouldStartConcurrentMark = false;
 369     OrderAccess::release();
 370 
 371     size_t max_live_data = _max_live_data;
 372     if (max_live_data == 0) {
 373       max_live_data = capacity * 0.2; // Very generous initial value.
 374     } else {
 375       max_live_data *= 1.3; // Add some wiggle room.
 376     }
 377     size_t max_cycle_allocated = _heap->max_allocated_gc();
 378     if (max_cycle_allocated == 0) {
 379       max_cycle_allocated = capacity * 0.3; // Very generous.
 380     } else {
 381       max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough.
 382     }
 383     size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data;
 384     if (used > threshold)
 385     {
 386       shouldStartConcurrentMark = true;
 387     }
 388 
 389     return shouldStartConcurrentMark;
 390   }
 391 
 392 };
 393 
 394 class GlobalHeuristics : public DynamicHeuristics {
 395 private:
 396   size_t _garbage;
 397   size_t _min_garbage;
 398 public:
 399   GlobalHeuristics() : DynamicHeuristics() {
 400     if (FLAG_IS_DEFAULT(ShenandoahGarbageThreshold)) {
 401       FLAG_SET_DEFAULT(ShenandoahGarbageThreshold, 90);
 402     }
 403   }
 404   virtual ~GlobalHeuristics() {}
 405 
 406   virtual void start_choose_collection_set() {
 407     _garbage = 0;
 408     size_t heap_garbage = ShenandoahHeap::heap()->garbage();
 409     _min_garbage =  heap_garbage * ShenandoahGarbageThreshold / 100;
 410   }
 411 
 412   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) {
 413     if (_garbage + immediate_garbage < _min_garbage) {
 414       _garbage += r->garbage();
 415       return true;
 416     } else {
 417       return false;
 418     }
 419   }
 420 
 421 };
 422 
 423 class RatioHeuristics : public DynamicHeuristics {
 424 private:
 425   size_t _garbage;
 426   size_t _live;
 427 public:
 428   RatioHeuristics() : DynamicHeuristics() {
 429     if (FLAG_IS_DEFAULT(ShenandoahGarbageThreshold)) {
 430       FLAG_SET_DEFAULT(ShenandoahGarbageThreshold, 95);
 431     }
 432   }
 433   virtual ~RatioHeuristics() {}
 434 
 435   virtual void start_choose_collection_set() {
 436     _garbage = 0;
 437     _live = 0;
 438   }
 439 
 440   virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) {
 441     size_t min_ratio = 100 - ShenandoahGarbageThreshold;
 442     if (_live * 100 / MAX2(_garbage + immediate_garbage, 1UL) < min_ratio) {
 443       _garbage += r->garbage();
 444       _live += r->get_live_data();
 445       return true;
 446     } else {
 447       return false;
 448     }
 449   }
 450 };
 451 
 452 ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() : _cycle_counter(0) {
 453 
 454   ShenandoahHeapRegion::setup_heap_region_size(initial_heap_byte_size(), max_heap_byte_size());
 455 
 456   initialize_all();
 457 
 458   _tracer = new (ResourceObj::C_HEAP, mtGC) ShenandoahTracer();
 459   _stw_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
 460   _conc_timer = new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer();
 461   _user_requested_gcs = 0;
 462   _allocation_failure_gcs = 0;
 463   _conc_gc_aborted = false;
 464 
 465   _phase_names[init_mark] = "Initial Mark Pauses (net)";
 466   _phase_names[init_mark_gross] = "Initial Mark Pauses (gross)";
 467   _phase_names[final_mark] = "Final Mark Pauses (net)";
 468   _phase_names[final_mark_gross] = "Final Mark Pauses (gross)";


 522 
 523   _phase_names[full_gc] = "Full GC Times";
 524   _phase_names[full_gc_mark] = "  Mark";
 525   _phase_names[full_gc_mark_drain_queues] = "    Drain Queues";
 526   _phase_names[full_gc_mark_weakrefs] = "    Weak References";
 527   _phase_names[full_gc_mark_class_unloading] = "    Class Unloading";
 528   _phase_names[full_gc_calculate_addresses] = "  Calculate Addresses";
 529   _phase_names[full_gc_adjust_pointers] = "  Adjust Pointers";
 530   _phase_names[full_gc_copy_objects] = "  Copy Objects";
 531 
 532   _phase_names[conc_mark] = "Concurrent Marking Times";
 533   _phase_names[conc_evac] = "Concurrent Evacuation Times";
 534 
 535   if (ShenandoahGCHeuristics != NULL) {
 536     if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) {
 537       log_info(gc, init)("Shenandoah heuristics: aggressive");
 538       _heuristics = new AggressiveHeuristics();
 539     } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) {
 540       log_info(gc, init)("Shenandoah heuristics: dynamic");
 541       _heuristics = new DynamicHeuristics();
 542     } else if (strcmp(ShenandoahGCHeuristics, "global") == 0) {
 543       log_info(gc, init)("Shenandoah heuristics: global");
 544       _heuristics = new GlobalHeuristics();
 545     } else if (strcmp(ShenandoahGCHeuristics, "ratio") == 0) {
 546       log_info(gc, init)("Shenandoah heuristics: ratio");
 547       _heuristics = new RatioHeuristics();
 548     } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) {
 549       log_info(gc, init)("Shenandoah heuristics: adaptive");
 550       _heuristics = new AdaptiveHeuristics();
 551     } else if (strcmp(ShenandoahGCHeuristics, "passive") == 0) {
 552       log_info(gc, init)("Shenandoah heuristics: passive");
 553       _heuristics = new PassiveHeuristics();
 554     } else {
 555       vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option");
 556     }
 557   } else {
 558       ShouldNotReachHere();
 559   }
 560   _phase_times = new ShenandoahPhaseTimes(MAX2(ConcGCThreads, ParallelGCThreads));
 561 }
 562 
 563 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() {
 564   return this;
 565 }
 566 
 567 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() {


< prev index next >