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 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 
 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 " and live = " SIZE_FORMAT " and _garbage_threshold = " SIZE_FORMAT "\n",
 127                             region->region_number(), region->garbage(), region->get_live_data(), _garbage_threshold);
 128 
 129       assert(! region->is_humongous(), "no humongous regions in collection set");
 130 
 131       if (region->get_live_data() == 0) {
 132         // We can recycle it right away and put it in the free set.
 133         ShenandoahHeap::heap()->decrease_used(region->used());
 134         region->recycle();
 135       } else {
 136         collection_set->add_region(region);
 137         region->set_is_in_collection_set(true);
 138       }
 139     } else {
 140       log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT " and live = " SIZE_FORMAT " and _garbage_threshold = " SIZE_FORMAT "\n",
 141                             region->region_number(), region->garbage(), region->get_live_data(), _garbage_threshold);
 142     }
 143   }
 144 
 145 }
 146 
 147 void ShenandoahHeuristics::choose_collection_set_min_garbage(ShenandoahCollectionSet* collection_set, size_t min_garbage) {
 148   ShenandoahHeapRegionSet* sorted_regions = ShenandoahHeap::heap()->sorted_regions();
 149   sorted_regions->sort(compareHeapRegionsByGarbage);
 150   size_t i = 0;
 151   size_t end = sorted_regions->active_regions();
 152 
 153   size_t garbage = 0;
 154   while (i < end && garbage < min_garbage) {
 155     ShenandoahHeapRegion* region = sorted_regions->get(i++);
 156     if (region->garbage() > _garbage_threshold && ! region->is_humongous() && ! region->is_pinned()) {
 157       collection_set->add_region(region);
 158       garbage += region->garbage();
 159       region->set_is_in_collection_set(true);
 160     }
 161   }
 162 }
 163 
 164 void ShenandoahHeuristics::choose_free_set(ShenandoahFreeSet* free_set) {
 165 
 166   ShenandoahHeapRegionSet* ordered_regions = ShenandoahHeap::heap()->regions();
 167   size_t i = 0;
 168   size_t end = ordered_regions->active_regions();
 169 
 170   while (i < end) {
 171     ShenandoahHeapRegion* region = ordered_regions->get(i++);
 172     if ((! region->is_in_collection_set())
 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     set_garbage_threshold(8);
 234   }
 235 
 236   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 237     // Never do concurrent GCs.
 238     return false;
 239   }
 240 
 241   virtual bool process_references() {
 242     // Randomly process refs with 50% chance.
 243     return (os::random() & 1) == 1;
 244   }
 245 
 246   virtual bool unload_classes() {
 247     // Randomly unload classes with 50% chance.
 248     return (os::random() & 1) == 1;
 249   }
 250 };
 251 
 252 class AggressiveHeuristics : public ShenandoahHeuristics {
 253 public:
 254   AggressiveHeuristics() : ShenandoahHeuristics() {
 255     set_garbage_threshold(8);
 256   }
 257 
 258   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 259     return true;
 260   }
 261 
 262   virtual bool process_references() {
 263     // Randomly process refs with 50% chance.
 264     return (os::random() & 1) == 1;
 265   }
 266 
 267   virtual bool unload_classes() {
 268     // Randomly unload classes with 50% chance.
 269     return (os::random() & 1) == 1;
 270   }
 271 };
 272 
 273 class DynamicHeuristics : public ShenandoahHeuristics {
 274 public:
 275   DynamicHeuristics() : ShenandoahHeuristics() {
 276     log_info(gc, init)("Shenandoah dynamic heuristics thresholds: allocation "SIZE_FORMAT", free "SIZE_FORMAT", garbage "SIZE_FORMAT,
 277                        ShenandoahAllocationThreshold,
 278                        ShenandoahFreeThreshold,
 279                        ShenandoahGarbageThreshold);
 280   }
 281 
 282   virtual ~DynamicHeuristics() {}
 283 
 284   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 285 
 286     bool shouldStartConcurrentMark = false;
 287 
 288     ShenandoahHeap* heap = ShenandoahHeap::heap();
 289     size_t free_capacity = heap->free_regions()->capacity();
 290     size_t free_used = heap->free_regions()->used();
 291     assert(free_used <= free_capacity, "must use less than capacity");
 292     size_t available =  free_capacity - free_used;
 293     uintx factor = heap->need_update_refs() ? ShenandoahFreeThreshold : ShenandoahInitialFreeThreshold;
 294     size_t targetStartMarking = (capacity * factor) / 100;
 295 
 296     size_t threshold_bytes_allocated = heap->capacity() * ShenandoahAllocationThreshold / 100;
 297     if (available < targetStartMarking &&
 298         heap->bytes_allocated_since_cm() > threshold_bytes_allocated)
 299     {
 300       // Need to check that an appropriate number of regions have
 301       // been allocated since last concurrent mark too.
 302       shouldStartConcurrentMark = true;
 303     }
 304 
 305     return shouldStartConcurrentMark;
 306   }
 307 
 308   virtual void choose_collection_set(ShenandoahCollectionSet* collection_set) {
 309     set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100);
 310     ShenandoahHeuristics::choose_collection_set(collection_set);
 311   }
 312 };
 313 
 314 
 315 class AdaptiveHeuristics : public ShenandoahHeuristics {
 316 private:
 317   size_t _max_live_data;
 318   double _used_threshold_factor;
 319   double _garbage_threshold_factor;
 320   double _allocation_threshold_factor;
 321 
 322   uintx _used_threshold;
 323   uintx _garbage_threshold;
 324   uintx _allocation_threshold;
 325 
 326 public:
 327   AdaptiveHeuristics() : ShenandoahHeuristics() {
 328     _max_live_data = 0;
 329 
 330     _used_threshold = 0;
 331     _garbage_threshold = 0;
 332     _allocation_threshold = 0;
 333 
 334     _used_threshold_factor = 0.;
 335     _garbage_threshold_factor = 0.1;
 336     _allocation_threshold_factor = 0.;
 337   }
 338 
 339   virtual ~AdaptiveHeuristics() {}
 340 
 341   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 342 
 343     ShenandoahHeap* _heap = ShenandoahHeap::heap();
 344     bool shouldStartConcurrentMark = false;
 345     OrderAccess::release();
 346 
 347     size_t max_live_data = _max_live_data;
 348     if (max_live_data == 0) {
 349       max_live_data = capacity * 0.2; // Very generous initial value.
 350     } else {
 351       max_live_data *= 1.3; // Add some wiggle room.
 352     }
 353     size_t max_cycle_allocated = _heap->max_allocated_gc();
 354     if (max_cycle_allocated == 0) {
 355       max_cycle_allocated = capacity * 0.3; // Very generous.
 356     } else {
 357       max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough.
 358     }
 359     size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data;
 360     if (used > threshold)
 361     {
 362       shouldStartConcurrentMark = true;
 363     }
 364 
 365     return shouldStartConcurrentMark;
 366   }
 367 
 368   virtual void choose_collection_set(ShenandoahCollectionSet* collection_set) {
 369     size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm();
 370     size_t min_garbage =  bytes_alloc/* * 1.1*/;
 371     set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100);
 372     ShenandoahHeuristics::choose_collection_set_min_garbage(collection_set, min_garbage);
 373 
 374     log_develop_trace(gc)("Garbage to be collected: "SIZE_FORMAT, collection_set->garbage());
 375     log_develop_trace(gc)("Objects to be evacuated: "SIZE_FORMAT, collection_set->live_data());
 376 
 377     _max_live_data = MAX2(_max_live_data, collection_set->live_data());
 378   }
 379 };
 380 
 381 ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() : _cycle_counter(0) {
 382 
 383   ShenandoahHeapRegion::setup_heap_region_size(initial_heap_byte_size(), max_heap_byte_size());
 384 
 385   initialize_all();
 386 
 387   _tracer = new (ResourceObj::C_HEAP, mtGC) ShenandoahTracer();
 388   _stw_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
 389   _conc_timer = new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer();
 390   _user_requested_gcs = 0;
 391   _allocation_failure_gcs = 0;
 392   _conc_gc_aborted = false;
 393 
 394   _phase_names[init_mark] = "Initial Mark Pauses (net)";
 395   _phase_names[init_mark_gross] = "Initial Mark Pauses (gross)";
 396   _phase_names[final_mark] = "Final Mark Pauses (net)";
 397   _phase_names[final_mark_gross] = "Final Mark Pauses (gross)";
 398   _phase_names[accumulate_stats] = "  Accumulate Stats";
 399   _phase_names[make_parsable] = "  Make Parsable";
 400   _phase_names[clear_liveness] = "  Clear Liveness";
 401   _phase_names[scan_roots] = "  Scan Roots";
 402   _phase_names[update_roots] = "  Update Roots";
 403   _phase_names[drain_satb] = "  Drain SATB";
 404   _phase_names[weakrefs] = "  Weak References";
 405   _phase_names[class_unloading] = "  Class Unloading";
 406   _phase_names[prepare_evac] = "  Prepare Evacuation";
 407   _phase_names[init_evac] = "  Initial Evacuation";
 408 
 409   _phase_names[scan_thread_roots] = "    Scan Thread Roots";
 410   _phase_names[scan_code_roots] = "    Scan Code Cache Roots";
 411   _phase_names[scan_string_table_roots] = "    Scan String Table  Roots";
 412   _phase_names[scan_universe_roots] = "    Scan Universe  Roots";
 413   _phase_names[scan_jni_roots] = "    Scan JNI  Roots";
 414   _phase_names[scan_jni_weak_roots] = "    Scan JNI Weak  Roots";
 415   _phase_names[scan_synchronizer_roots] = "    Scan Synchronizer  Roots";
 416   _phase_names[scan_flat_profiler_roots] = "    Scan Flat Profiler Roots";
 417   _phase_names[scan_management_roots] = "    Scan Management Roots";
 418   _phase_names[scan_system_dictionary_roots] = "    Scan System Dictionary Roots";
 419   _phase_names[scan_cldg_roots] = "    Scan CLDG  Roots";
 420   _phase_names[scan_jvmti_roots] = "    Scan JVMTI Roots";
 421 
 422   _phase_names[update_thread_roots] = "    Update Thread Roots";
 423   _phase_names[update_code_roots] = "    Update Code Cache Roots";
 424   _phase_names[update_string_table_roots] = "    Update String Table  Roots";
 425   _phase_names[update_universe_roots] = "    Update Universe  Roots";
 426   _phase_names[update_jni_roots] = "    Update JNI  Roots";
 427   _phase_names[update_jni_weak_roots] = "    Update JNI Weak  Roots";
 428   _phase_names[update_synchronizer_roots] = "    Update Synchronizer  Roots";
 429   _phase_names[update_flat_profiler_roots] = "    Update Flat Profiler Roots";
 430   _phase_names[update_management_roots] = "    Update Management Roots";
 431   _phase_names[update_system_dictionary_roots] = "    Update System Dictionary Roots";
 432   _phase_names[update_cldg_roots] = "    Update CLDG  Roots";
 433   _phase_names[update_jvmti_roots] = "    Update JVMTI Roots";
 434 
 435   _phase_names[evac_thread_roots] = "    Evacuate Thread Roots";
 436   _phase_names[evac_code_roots] = "    Evacuate Code Cache Roots";
 437   _phase_names[evac_string_table_roots] = "    Evacuate String Table  Roots";
 438   _phase_names[evac_universe_roots] = "    Evacuate Universe  Roots";
 439   _phase_names[evac_jni_roots] = "    Evacuate JNI  Roots";
 440   _phase_names[evac_jni_weak_roots] = "    Evacuate JNI Weak  Roots";
 441   _phase_names[evac_synchronizer_roots] = "    Evacuate Synchronizer  Roots";
 442   _phase_names[evac_flat_profiler_roots] = "    Evacuate Flat Profiler Roots";
 443   _phase_names[evac_management_roots] = "    Evacuate Management Roots";
 444   _phase_names[evac_system_dictionary_roots] = "    Evacuate System Dictionary Roots";
 445   _phase_names[evac_cldg_roots] = "    Evacuate CLDG  Roots";
 446   _phase_names[evac_jvmti_roots] = "    Evacuate JVMTI Roots";
 447 
 448   _phase_names[recycle_regions] = "  Recycle regions";
 449   _phase_names[reset_bitmaps] = "ResetBitmaps";
 450   _phase_names[resize_tlabs] = "Resize TLABs";
 451 
 452   _phase_names[full_gc] = "Full GC Times";
 453   _phase_names[full_gc_mark] = "  Mark";
 454   _phase_names[full_gc_mark_weakrefs] = "    Weak References";
 455   _phase_names[full_gc_mark_class_unloading] = "    Class Unloading";
 456   _phase_names[full_gc_calculate_addresses] = "  Calculate Addresses";
 457   _phase_names[full_gc_adjust_pointers] = "  Adjust Pointers";
 458   _phase_names[full_gc_copy_objects] = "  Copy Objects";
 459 
 460   _phase_names[conc_mark] = "Concurrent Marking Times";
 461   _phase_names[conc_evac] = "Concurrent Evacuation Times";
 462 
 463   if (ShenandoahGCHeuristics != NULL) {
 464     if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) {
 465       log_info(gc, init)("Shenandoah heuristics: aggressive");
 466       _heuristics = new AggressiveHeuristics();
 467     } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) {
 468       log_info(gc, init)("Shenandoah heuristics: dynamic");
 469       _heuristics = new DynamicHeuristics();
 470     } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) {
 471       log_info(gc, init)("Shenandoah heuristics: adaptive");
 472       _heuristics = new AdaptiveHeuristics();
 473     } else if (strcmp(ShenandoahGCHeuristics, "passive") == 0) {
 474       log_info(gc, init)("Shenandoah heuristics: passive");
 475       _heuristics = new PassiveHeuristics();
 476     } else {
 477       vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option");
 478     }
 479   } else {
 480       ShouldNotReachHere();
 481   }
 482   _phase_times = new ShenandoahPhaseTimes(MAX2(ConcGCThreads, ParallelGCThreads));
 483 }
 484 
 485 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() {
 486   return this;
 487 }
 488 
 489 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() {
 490   return BarrierSet::ShenandoahBarrierSet;
 491 }
 492 
 493 HeapWord* ShenandoahCollectorPolicy::mem_allocate_work(size_t size,
 494                                                        bool is_tlab,
 495                                                        bool* gc_overhead_limit_was_exceeded) {
 496   guarantee(false, "Not using this policy feature yet.");
 497   return NULL;
 498 }
 499 
 500 HeapWord* ShenandoahCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) {
 501   guarantee(false, "Not using this policy feature yet.");
 502   return NULL;
 503 }
 504 
 505 void ShenandoahCollectorPolicy::initialize_alignments() {
 506 
 507   // This is expected by our algorithm for ShenandoahHeap::heap_region_containing().
 508   _space_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 509   _heap_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 510 }
 511 
 512 void ShenandoahCollectorPolicy::post_heap_initialize() {
 513   // Nothing to do here (yet).
 514 }
 515 
 516 void ShenandoahCollectorPolicy::record_bytes_allocated(size_t bytes) {
 517   _heuristics->record_bytes_allocated(bytes);
 518 }
 519 
 520 void ShenandoahCollectorPolicy::record_bytes_start_CM(size_t bytes) {
 521   _heuristics->record_bytes_start_CM(bytes);
 522 }
 523 
 524 void ShenandoahCollectorPolicy::record_bytes_end_CM(size_t bytes) {
 525   _heuristics->record_bytes_end_CM(bytes);
 526 }
 527 
 528 void ShenandoahCollectorPolicy::record_bytes_reclaimed(size_t bytes) {
 529   _heuristics->record_bytes_reclaimed(bytes);
 530 }
 531 
 532 void ShenandoahCollectorPolicy::record_user_requested_gc() {
 533   _user_requested_gcs++;
 534 }
 535 
 536 void ShenandoahCollectorPolicy::record_allocation_failure_gc() {
 537   _allocation_failure_gcs++;
 538 }
 539 
 540 bool ShenandoahCollectorPolicy::should_start_concurrent_mark(size_t used,
 541                                                              size_t capacity) {
 542   return _heuristics->should_start_concurrent_mark(used, capacity);
 543 }
 544 
 545 void ShenandoahCollectorPolicy::choose_collection_set(ShenandoahCollectionSet* collection_set) {
 546   _heuristics->choose_collection_set(collection_set);
 547 }
 548 
 549 void ShenandoahCollectorPolicy::choose_free_set(ShenandoahFreeSet* free_set) {
 550    _heuristics->choose_free_set(free_set);
 551 }
 552 
 553 
 554 bool ShenandoahCollectorPolicy::process_references() {
 555   return _heuristics->process_references();
 556 }
 557 
 558 bool ShenandoahCollectorPolicy::unload_classes() {
 559   return _heuristics->unload_classes();
 560 }
 561 
 562 void ShenandoahCollectorPolicy::print_tracing_info(outputStream* out) {
 563   for (uint i = 0; i < _num_phases; i++) {
 564     if (_timing_data[i]._ms.maximum() != 0) {
 565       print_summary_sd(out, _phase_names[i], &(_timing_data[i]._ms));
 566     }
 567   }
 568   out->print_cr("User requested GCs: "SIZE_FORMAT, _user_requested_gcs);
 569   out->print_cr("Allocation failure GCs: "SIZE_FORMAT, _allocation_failure_gcs);
 570 
 571   out->print_cr(" ");
 572   double total_sum = _timing_data[init_mark_gross]._ms.sum() +
 573                      _timing_data[final_mark_gross]._ms.sum();
 574   double total_avg = (_timing_data[init_mark_gross]._ms.avg() +
 575                       _timing_data[final_mark_gross]._ms.avg()) / 2.0;
 576   double total_max = MAX2(_timing_data[init_mark_gross]._ms.maximum(),
 577                           _timing_data[final_mark_gross]._ms.maximum());
 578 
 579   out->print_cr("%-27s = %8.2lf s, avg = %8.2lf ms, max = %8.2lf ms",
 580                          "Total", total_sum / 1000.0, total_avg, total_max);
 581 
 582 }
 583 
 584 void ShenandoahCollectorPolicy::print_summary_sd(outputStream* out, const char* str, const NumberSeq* seq)  {
 585   double sum = seq->sum();
 586   out->print("%-34s = %8.2lf s (avg = %8.2lf ms)",
 587                       str, sum / 1000.0, seq->avg());
 588   out->print_cr("  %s = "INT32_FORMAT_W(5)", std dev = %8.2lf ms, max = %8.2lf ms)",
 589                          "(num", seq->num(), seq->sd(), seq->maximum());
 590 }
 591 
 592 void ShenandoahCollectorPolicy::increase_cycle_counter() {
 593   _cycle_counter++;
 594 }
 595 
 596 size_t ShenandoahCollectorPolicy::cycle_counter() const {
 597   return _cycle_counter;
 598 }
 599 
 600 ShenandoahPhaseTimes* ShenandoahCollectorPolicy::phase_times() {
 601   return _phase_times;
 602 }