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[drain_queues] = "  Drain Queues";
 405   _phase_names[weakrefs] = "  Weak References";
 406   _phase_names[class_unloading] = "  Class Unloading";
 407   _phase_names[prepare_evac] = "  Prepare Evacuation";
 408   _phase_names[init_evac] = "  Initial Evacuation";
 409 
 410   _phase_names[scan_thread_roots] = "    Scan Thread Roots";
 411   _phase_names[scan_code_roots] = "    Scan Code Cache Roots";
 412   _phase_names[scan_string_table_roots] = "    Scan String Table  Roots";
 413   _phase_names[scan_universe_roots] = "    Scan Universe  Roots";
 414   _phase_names[scan_jni_roots] = "    Scan JNI  Roots";
 415   _phase_names[scan_jni_weak_roots] = "    Scan JNI Weak  Roots";
 416   _phase_names[scan_synchronizer_roots] = "    Scan Synchronizer  Roots";
 417   _phase_names[scan_flat_profiler_roots] = "    Scan Flat Profiler Roots";
 418   _phase_names[scan_management_roots] = "    Scan Management Roots";
 419   _phase_names[scan_system_dictionary_roots] = "    Scan System Dictionary Roots";
 420   _phase_names[scan_cldg_roots] = "    Scan CLDG  Roots";
 421   _phase_names[scan_jvmti_roots] = "    Scan JVMTI Roots";
 422 
 423   _phase_names[update_thread_roots] = "    Update Thread Roots";
 424   _phase_names[update_code_roots] = "    Update Code Cache Roots";
 425   _phase_names[update_string_table_roots] = "    Update String Table  Roots";
 426   _phase_names[update_universe_roots] = "    Update Universe  Roots";
 427   _phase_names[update_jni_roots] = "    Update JNI  Roots";
 428   _phase_names[update_jni_weak_roots] = "    Update JNI Weak  Roots";
 429   _phase_names[update_synchronizer_roots] = "    Update Synchronizer  Roots";
 430   _phase_names[update_flat_profiler_roots] = "    Update Flat Profiler Roots";
 431   _phase_names[update_management_roots] = "    Update Management Roots";
 432   _phase_names[update_system_dictionary_roots] = "    Update System Dictionary Roots";
 433   _phase_names[update_cldg_roots] = "    Update CLDG  Roots";
 434   _phase_names[update_jvmti_roots] = "    Update JVMTI Roots";
 435 
 436   _phase_names[evac_thread_roots] = "    Evacuate Thread Roots";
 437   _phase_names[evac_code_roots] = "    Evacuate Code Cache Roots";
 438   _phase_names[evac_string_table_roots] = "    Evacuate String Table  Roots";
 439   _phase_names[evac_universe_roots] = "    Evacuate Universe  Roots";
 440   _phase_names[evac_jni_roots] = "    Evacuate JNI  Roots";
 441   _phase_names[evac_jni_weak_roots] = "    Evacuate JNI Weak  Roots";
 442   _phase_names[evac_synchronizer_roots] = "    Evacuate Synchronizer  Roots";
 443   _phase_names[evac_flat_profiler_roots] = "    Evacuate Flat Profiler Roots";
 444   _phase_names[evac_management_roots] = "    Evacuate Management Roots";
 445   _phase_names[evac_system_dictionary_roots] = "    Evacuate System Dictionary Roots";
 446   _phase_names[evac_cldg_roots] = "    Evacuate CLDG  Roots";
 447   _phase_names[evac_jvmti_roots] = "    Evacuate JVMTI Roots";
 448 
 449   _phase_names[recycle_regions] = "  Recycle regions";
 450   _phase_names[reset_bitmaps] = "ResetBitmaps";
 451   _phase_names[resize_tlabs] = "Resize TLABs";
 452 
 453   _phase_names[full_gc] = "Full GC Times";
 454   _phase_names[full_gc_mark] = "  Mark";
 455   _phase_names[full_gc_mark_drain_queues] = "    Drain Queues";
 456   _phase_names[full_gc_mark_weakrefs] = "    Weak References";
 457   _phase_names[full_gc_mark_class_unloading] = "    Class Unloading";
 458   _phase_names[full_gc_calculate_addresses] = "  Calculate Addresses";
 459   _phase_names[full_gc_adjust_pointers] = "  Adjust Pointers";
 460   _phase_names[full_gc_copy_objects] = "  Copy Objects";
 461 
 462   _phase_names[conc_mark] = "Concurrent Marking Times";
 463   _phase_names[conc_evac] = "Concurrent Evacuation Times";
 464 
 465   if (ShenandoahGCHeuristics != NULL) {
 466     if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) {
 467       log_info(gc, init)("Shenandoah heuristics: aggressive");
 468       _heuristics = new AggressiveHeuristics();
 469     } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) {
 470       log_info(gc, init)("Shenandoah heuristics: dynamic");
 471       _heuristics = new DynamicHeuristics();
 472     } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) {
 473       log_info(gc, init)("Shenandoah heuristics: adaptive");
 474       _heuristics = new AdaptiveHeuristics();
 475     } else if (strcmp(ShenandoahGCHeuristics, "passive") == 0) {
 476       log_info(gc, init)("Shenandoah heuristics: passive");
 477       _heuristics = new PassiveHeuristics();
 478     } else {
 479       vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option");
 480     }
 481   } else {
 482       ShouldNotReachHere();
 483   }
 484   _phase_times = new ShenandoahPhaseTimes(MAX2(ConcGCThreads, ParallelGCThreads));
 485 }
 486 
 487 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() {
 488   return this;
 489 }
 490 
 491 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() {
 492   return BarrierSet::ShenandoahBarrierSet;
 493 }
 494 
 495 HeapWord* ShenandoahCollectorPolicy::mem_allocate_work(size_t size,
 496                                                        bool is_tlab,
 497                                                        bool* gc_overhead_limit_was_exceeded) {
 498   guarantee(false, "Not using this policy feature yet.");
 499   return NULL;
 500 }
 501 
 502 HeapWord* ShenandoahCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) {
 503   guarantee(false, "Not using this policy feature yet.");
 504   return NULL;
 505 }
 506 
 507 void ShenandoahCollectorPolicy::initialize_alignments() {
 508 
 509   // This is expected by our algorithm for ShenandoahHeap::heap_region_containing().
 510   _space_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 511   _heap_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 512 }
 513 
 514 void ShenandoahCollectorPolicy::post_heap_initialize() {
 515   // Nothing to do here (yet).
 516 }
 517 
 518 void ShenandoahCollectorPolicy::record_bytes_allocated(size_t bytes) {
 519   _heuristics->record_bytes_allocated(bytes);
 520 }
 521 
 522 void ShenandoahCollectorPolicy::record_bytes_start_CM(size_t bytes) {
 523   _heuristics->record_bytes_start_CM(bytes);
 524 }
 525 
 526 void ShenandoahCollectorPolicy::record_bytes_end_CM(size_t bytes) {
 527   _heuristics->record_bytes_end_CM(bytes);
 528 }
 529 
 530 void ShenandoahCollectorPolicy::record_bytes_reclaimed(size_t bytes) {
 531   _heuristics->record_bytes_reclaimed(bytes);
 532 }
 533 
 534 void ShenandoahCollectorPolicy::record_user_requested_gc() {
 535   _user_requested_gcs++;
 536 }
 537 
 538 void ShenandoahCollectorPolicy::record_allocation_failure_gc() {
 539   _allocation_failure_gcs++;
 540 }
 541 
 542 bool ShenandoahCollectorPolicy::should_start_concurrent_mark(size_t used,
 543                                                              size_t capacity) {
 544   return _heuristics->should_start_concurrent_mark(used, capacity);
 545 }
 546 
 547 void ShenandoahCollectorPolicy::choose_collection_set(ShenandoahCollectionSet* collection_set) {
 548   _heuristics->choose_collection_set(collection_set);
 549 }
 550 
 551 void ShenandoahCollectorPolicy::choose_free_set(ShenandoahFreeSet* free_set) {
 552    _heuristics->choose_free_set(free_set);
 553 }
 554 
 555 
 556 bool ShenandoahCollectorPolicy::process_references() {
 557   return _heuristics->process_references();
 558 }
 559 
 560 bool ShenandoahCollectorPolicy::unload_classes() {
 561   return _heuristics->unload_classes();
 562 }
 563 
 564 void ShenandoahCollectorPolicy::print_tracing_info(outputStream* out) {
 565   for (uint i = 0; i < _num_phases; i++) {
 566     if (_timing_data[i]._ms.maximum() != 0) {
 567       print_summary_sd(out, _phase_names[i], &(_timing_data[i]._ms));
 568     }
 569   }
 570   out->print_cr("User requested GCs: "SIZE_FORMAT, _user_requested_gcs);
 571   out->print_cr("Allocation failure GCs: "SIZE_FORMAT, _allocation_failure_gcs);
 572 
 573   out->print_cr(" ");
 574   double total_sum = _timing_data[init_mark_gross]._ms.sum() +
 575                      _timing_data[final_mark_gross]._ms.sum();
 576   double total_avg = (_timing_data[init_mark_gross]._ms.avg() +
 577                       _timing_data[final_mark_gross]._ms.avg()) / 2.0;
 578   double total_max = MAX2(_timing_data[init_mark_gross]._ms.maximum(),
 579                           _timing_data[final_mark_gross]._ms.maximum());
 580 
 581   out->print_cr("%-27s = %8.2lf s, avg = %8.2lf ms, max = %8.2lf ms",
 582                          "Total", total_sum / 1000.0, total_avg, total_max);
 583 
 584 }
 585 
 586 void ShenandoahCollectorPolicy::print_summary_sd(outputStream* out, const char* str, const NumberSeq* seq)  {
 587   double sum = seq->sum();
 588   out->print("%-34s = %8.2lf s (avg = %8.2lf ms)",
 589                       str, sum / 1000.0, seq->avg());
 590   out->print_cr("  %s = "INT32_FORMAT_W(5)", std dev = %8.2lf ms, max = %8.2lf ms)",
 591                          "(num", seq->num(), seq->sd(), seq->maximum());
 592 }
 593 
 594 void ShenandoahCollectorPolicy::increase_cycle_counter() {
 595   _cycle_counter++;
 596 }
 597 
 598 size_t ShenandoahCollectorPolicy::cycle_counter() const {
 599   return _cycle_counter;
 600 }
 601 
 602 ShenandoahPhaseTimes* ShenandoahCollectorPolicy::phase_times() {
 603   return _phase_times;
 604 }