1 /*
   2  * Copyright (c) 2013, 2015, Red Hat, Inc. and/or its affiliates.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  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) {
 181   for (uint i = 0; i < ShenandoahPhaseTimes::GCParPhasesSentinel; i++) {
 182     _phase_times->reset(i);
 183   }
 184 }
 185 
 186 void ShenandoahCollectorPolicy::record_workers_end(TimingPhase phase) {
 187   if (phase != _num_phases) {
 188     for (uint i = 0; i < ShenandoahPhaseTimes::GCParPhasesSentinel; i++) {
 189       double t = _phase_times->average(i);
 190       _timing_data[phase + i]._ms.add(t * 1000.0);
 191     }
 192   }
 193 }
 194 
 195 void ShenandoahCollectorPolicy::record_phase_start(TimingPhase phase) {
 196   _timing_data[phase]._start = os::elapsedTime();
 197 
 198 }
 199 
 200 void ShenandoahCollectorPolicy::record_phase_end(TimingPhase phase) {
 201   double end = os::elapsedTime();
 202   double elapsed = end - _timing_data[phase]._start;
 203   _timing_data[phase]._ms.add(elapsed * 1000);
 204 
 205 }
 206 
 207 void ShenandoahCollectorPolicy::report_concgc_cancelled() {
 208 }
 209 
 210 void ShenandoahHeuristics::record_bytes_allocated(size_t bytes) {
 211   _bytes_allocated_since_CM = bytes;
 212   _bytes_allocated_start_CM = bytes;
 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)";
 469   _phase_names[accumulate_stats] = "  Accumulate Stats";
 470   _phase_names[make_parsable] = "  Make Parsable";
 471   _phase_names[clear_liveness] = "  Clear Liveness";
 472   _phase_names[scan_roots] = "  Scan Roots";
 473   _phase_names[update_roots] = "  Update Roots";
 474   _phase_names[drain_satb] = "  Drain SATB";
 475   _phase_names[weakrefs] = "  Weak References";
 476   _phase_names[class_unloading] = "  Class Unloading";
 477   _phase_names[prepare_evac] = "  Prepare Evacuation";
 478   _phase_names[init_evac] = "  Initial Evacuation";
 479 
 480   _phase_names[scan_thread_roots] = "    Scan Thread Roots";
 481   _phase_names[scan_code_roots] = "    Scan Code Cache Roots";
 482   _phase_names[scan_string_table_roots] = "    Scan String Table  Roots";
 483   _phase_names[scan_universe_roots] = "    Scan Universe  Roots";
 484   _phase_names[scan_jni_roots] = "    Scan JNI  Roots";
 485   _phase_names[scan_jni_weak_roots] = "    Scan JNI Weak  Roots";
 486   _phase_names[scan_synchronizer_roots] = "    Scan Synchronizer  Roots";
 487   _phase_names[scan_flat_profiler_roots] = "    Scan Flat Profiler Roots";
 488   _phase_names[scan_management_roots] = "    Scan Management Roots";
 489   _phase_names[scan_system_dictionary_roots] = "    Scan System Dictionary Roots";
 490   _phase_names[scan_cldg_roots] = "    Scan CLDG  Roots";
 491   _phase_names[scan_jvmti_roots] = "    Scan JVMTI Roots";
 492 
 493   _phase_names[update_thread_roots] = "    Update Thread Roots";
 494   _phase_names[update_code_roots] = "    Update Code Cache Roots";
 495   _phase_names[update_string_table_roots] = "    Update String Table  Roots";
 496   _phase_names[update_universe_roots] = "    Update Universe  Roots";
 497   _phase_names[update_jni_roots] = "    Update JNI  Roots";
 498   _phase_names[update_jni_weak_roots] = "    Update JNI Weak  Roots";
 499   _phase_names[update_synchronizer_roots] = "    Update Synchronizer  Roots";
 500   _phase_names[update_flat_profiler_roots] = "    Update Flat Profiler Roots";
 501   _phase_names[update_management_roots] = "    Update Management Roots";
 502   _phase_names[update_system_dictionary_roots] = "    Update System Dictionary Roots";
 503   _phase_names[update_cldg_roots] = "    Update CLDG  Roots";
 504   _phase_names[update_jvmti_roots] = "    Update JVMTI Roots";
 505 
 506   _phase_names[evac_thread_roots] = "    Evacuate Thread Roots";
 507   _phase_names[evac_code_roots] = "    Evacuate Code Cache Roots";
 508   _phase_names[evac_string_table_roots] = "    Evacuate String Table  Roots";
 509   _phase_names[evac_universe_roots] = "    Evacuate Universe  Roots";
 510   _phase_names[evac_jni_roots] = "    Evacuate JNI  Roots";
 511   _phase_names[evac_jni_weak_roots] = "    Evacuate JNI Weak  Roots";
 512   _phase_names[evac_synchronizer_roots] = "    Evacuate Synchronizer  Roots";
 513   _phase_names[evac_flat_profiler_roots] = "    Evacuate Flat Profiler Roots";
 514   _phase_names[evac_management_roots] = "    Evacuate Management Roots";
 515   _phase_names[evac_system_dictionary_roots] = "    Evacuate System Dictionary Roots";
 516   _phase_names[evac_cldg_roots] = "    Evacuate CLDG  Roots";
 517   _phase_names[evac_jvmti_roots] = "    Evacuate JVMTI Roots";
 518 
 519   _phase_names[recycle_regions] = "  Recycle regions";
 520   _phase_names[reset_bitmaps] = "ResetBitmaps";
 521   _phase_names[resize_tlabs] = "Resize TLABs";
 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() {
 568   return BarrierSet::ShenandoahBarrierSet;
 569 }
 570 
 571 HeapWord* ShenandoahCollectorPolicy::mem_allocate_work(size_t size,
 572                                                        bool is_tlab,
 573                                                        bool* gc_overhead_limit_was_exceeded) {
 574   guarantee(false, "Not using this policy feature yet.");
 575   return NULL;
 576 }
 577 
 578 HeapWord* ShenandoahCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) {
 579   guarantee(false, "Not using this policy feature yet.");
 580   return NULL;
 581 }
 582 
 583 void ShenandoahCollectorPolicy::initialize_alignments() {
 584 
 585   // This is expected by our algorithm for ShenandoahHeap::heap_region_containing().
 586   _space_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 587   _heap_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 588 }
 589 
 590 void ShenandoahCollectorPolicy::post_heap_initialize() {
 591   // Nothing to do here (yet).
 592 }
 593 
 594 void ShenandoahCollectorPolicy::record_bytes_allocated(size_t bytes) {
 595   _heuristics->record_bytes_allocated(bytes);
 596 }
 597 
 598 void ShenandoahCollectorPolicy::record_bytes_start_CM(size_t bytes) {
 599   _heuristics->record_bytes_start_CM(bytes);
 600 }
 601 
 602 void ShenandoahCollectorPolicy::record_bytes_end_CM(size_t bytes) {
 603   _heuristics->record_bytes_end_CM(bytes);
 604 }
 605 
 606 void ShenandoahCollectorPolicy::record_bytes_reclaimed(size_t bytes) {
 607   _heuristics->record_bytes_reclaimed(bytes);
 608 }
 609 
 610 void ShenandoahCollectorPolicy::record_user_requested_gc() {
 611   _user_requested_gcs++;
 612 }
 613 
 614 void ShenandoahCollectorPolicy::record_allocation_failure_gc() {
 615   _allocation_failure_gcs++;
 616 }
 617 
 618 bool ShenandoahCollectorPolicy::should_start_concurrent_mark(size_t used,
 619                                                              size_t capacity) {
 620   return _heuristics->should_start_concurrent_mark(used, capacity);
 621 }
 622 
 623 void ShenandoahCollectorPolicy::choose_collection_set(ShenandoahCollectionSet* collection_set) {
 624   _heuristics->choose_collection_set(collection_set);
 625 }
 626 
 627 void ShenandoahCollectorPolicy::choose_free_set(ShenandoahFreeSet* free_set) {
 628    _heuristics->choose_free_set(free_set);
 629 }
 630 
 631 
 632 bool ShenandoahCollectorPolicy::process_references() {
 633   return _heuristics->process_references();
 634 }
 635 
 636 bool ShenandoahCollectorPolicy::unload_classes() {
 637   return _heuristics->unload_classes();
 638 }
 639 
 640 void ShenandoahCollectorPolicy::print_tracing_info(outputStream* out) {
 641   for (uint i = 0; i < _num_phases; i++) {
 642     if (_timing_data[i]._ms.maximum() != 0) {
 643       print_summary_sd(out, _phase_names[i], &(_timing_data[i]._ms));
 644     }
 645   }
 646   out->print_cr("User requested GCs: "SIZE_FORMAT, _user_requested_gcs);
 647   out->print_cr("Allocation failure GCs: "SIZE_FORMAT, _allocation_failure_gcs);
 648 
 649   out->print_cr(" ");
 650   double total_sum = _timing_data[init_mark_gross]._ms.sum() +
 651                      _timing_data[final_mark_gross]._ms.sum();
 652   double total_avg = (_timing_data[init_mark_gross]._ms.avg() +
 653                       _timing_data[final_mark_gross]._ms.avg()) / 2.0;
 654   double total_max = MAX2(_timing_data[init_mark_gross]._ms.maximum(),
 655                           _timing_data[final_mark_gross]._ms.maximum());
 656 
 657   out->print_cr("%-27s = %8.2lf s, avg = %8.2lf ms, max = %8.2lf ms",
 658                          "Total", total_sum / 1000.0, total_avg, total_max);
 659 
 660 }
 661 
 662 void ShenandoahCollectorPolicy::print_summary_sd(outputStream* out, const char* str, const NumberSeq* seq)  {
 663   double sum = seq->sum();
 664   out->print("%-34s = %8.2lf s (avg = %8.2lf ms)",
 665                       str, sum / 1000.0, seq->avg());
 666   out->print_cr("  %s = "INT32_FORMAT_W(5)", std dev = %8.2lf ms, max = %8.2lf ms)",
 667                          "(num", seq->num(), seq->sd(), seq->maximum());
 668 }
 669 
 670 void ShenandoahCollectorPolicy::increase_cycle_counter() {
 671   _cycle_counter++;
 672 }
 673 
 674 size_t ShenandoahCollectorPolicy::cycle_counter() const {
 675   return _cycle_counter;
 676 }
 677 
 678 ShenandoahPhaseTimes* ShenandoahCollectorPolicy::phase_times() {
 679   return _phase_times;
 680 }