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/shenandoah/shenandoahCollectorPolicy.hpp"
  25 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  26 
  27 class ShenandoahHeuristics : public CHeapObj<mtGC> {
  28 
  29   NumberSeq _allocation_rate_bytes;
  30   NumberSeq _reclamation_rate_bytes;
  31 
  32   size_t _bytes_allocated_since_CM;
  33   size_t _bytes_reclaimed_this_cycle;
  34 
  35 protected:
  36   size_t _bytes_allocated_start_CM;
  37   size_t _bytes_allocated_during_CM;
  38 
  39 public:
  40 
  41   ShenandoahHeuristics();
  42 
  43   void record_bytes_allocated(size_t bytes);
  44   void record_bytes_reclaimed(size_t bytes);
  45   void record_bytes_start_CM(size_t bytes);
  46   void record_bytes_end_CM(size_t bytes);
  47 
  48   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const=0;
  49   virtual bool update_refs_early();
  50   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
  51                                                ShenandoahHeapRegionSet* collection_set,
  52                                                ShenandoahHeapRegionSet* free_set) =0;
  53   void print_tracing_info();
  54 };
  55 
  56 ShenandoahHeuristics::ShenandoahHeuristics() :
  57   _bytes_allocated_since_CM(0),
  58   _bytes_reclaimed_this_cycle(0),
  59   _bytes_allocated_start_CM(0),
  60   _bytes_allocated_during_CM(0)
  61 {
  62   if (PrintGCDetails)
  63     tty->print_cr("initializing heuristics");
  64 }
  65 
  66 void ShenandoahCollectorPolicy::record_phase_start(TimingPhase phase) {
  67   _timing_data[phase]._start = os::elapsedTime();
  68 
  69   if (PrintGCTimeStamps) {
  70     if (phase == init_mark)
  71       _tracer->report_gc_start(GCCause::_shenandoah_init_mark, _conc_timer->gc_start());
  72     else if (phase == full_gc)
  73       _tracer->report_gc_start(GCCause::_last_ditch_collection, _stw_timer->gc_start());
  74 
  75     gclog_or_tty->gclog_stamp(_tracer->gc_id());
  76     gclog_or_tty->print("[GC %s start", _phase_names[phase]);
  77     ShenandoahHeap* heap = (ShenandoahHeap*) Universe::heap();
  78 
  79     gclog_or_tty->print(" total = " SIZE_FORMAT " K, used = " SIZE_FORMAT " K free = " SIZE_FORMAT " K", heap->capacity()/ K, heap->used() /K,
  80                         ((heap->capacity() - heap->used())/K) );
  81 
  82     if (heap->calculateUsed() != heap->used()) {
  83       gclog_or_tty->print("calc used = " SIZE_FORMAT " K heap used = " SIZE_FORMAT " K",
  84                             heap->calculateUsed() / K, heap->used() / K);
  85     }
  86     //    assert(heap->calculateUsed() == heap->used(), "Just checking");
  87     gclog_or_tty->print_cr("]");
  88   }
  89 }
  90 
  91 void ShenandoahCollectorPolicy::record_phase_end(TimingPhase phase) {
  92   double end = os::elapsedTime();
  93   double elapsed = end - _timing_data[phase]._start;
  94   _timing_data[phase]._ms.add(elapsed * 1000);
  95 
  96   if (ShenandoahGCVerbose && PrintGCDetails) {
  97     tty->print_cr("PolicyPrint: %s "SIZE_FORMAT" took %lf ms", _phase_names[phase],
  98                   _timing_data[phase]._count++, elapsed * 1000);
  99   }
 100   if (PrintGCTimeStamps) {
 101     ShenandoahHeap* heap = (ShenandoahHeap*) Universe::heap();
 102     gclog_or_tty->gclog_stamp(_tracer->gc_id());
 103 
 104     gclog_or_tty->print("[GC %s end, %lf secs", _phase_names[phase], elapsed );
 105     gclog_or_tty->print(" total = " SIZE_FORMAT " K, used = " SIZE_FORMAT " K free = " SIZE_FORMAT " K", heap->capacity()/ K, heap->used() /K,
 106                         ((heap->capacity() - heap->used())/K) );
 107 
 108     if (heap->calculateUsed() != heap->used()) {
 109       gclog_or_tty->print("calc used = " SIZE_FORMAT " K heap used = " SIZE_FORMAT " K",
 110                             heap->calculateUsed() / K, heap->used() / K);
 111     }
 112     //    assert(heap->calculateUsed() == heap->used(), "Stashed heap used must be equal to calculated heap used");
 113     gclog_or_tty->print_cr("]");
 114 
 115     if (phase == recycle_regions) {
 116       _tracer->report_gc_end(_conc_timer->gc_end(), _conc_timer->time_partitions());
 117     } else if (phase == full_gc) {
 118       _tracer->report_gc_end(_stw_timer->gc_end(), _stw_timer->time_partitions());
 119     } else if (phase == conc_mark || phase == conc_evac || phase == conc_uprefs || phase == prepare_evac) {
 120       if (_conc_gc_aborted) {
 121         _tracer->report_gc_end(_conc_timer->gc_end(), _conc_timer->time_partitions());
 122         clear_conc_gc_aborted();
 123       }
 124     } else if (phase == final_evac) {
 125       ShenandoahHeap* heap = ShenandoahHeap::heap();
 126       this->record_bytes_end_CM(heap->_bytesAllocSinceCM);
 127     }
 128   }
 129 }
 130 
 131 void ShenandoahCollectorPolicy::report_concgc_cancelled() {
 132   if (PrintGCTimeStamps)  {
 133     gclog_or_tty->print("Concurrent GC Cancelled\n");
 134     set_conc_gc_aborted();
 135     //    _tracer->report_gc_end(_conc_timer->gc_end(), _conc_timer->time_partitions());
 136   }
 137 }
 138 
 139 bool ShenandoahHeuristics::update_refs_early() {
 140   return ShenandoahUpdateRefsEarly;
 141 }
 142 
 143 void ShenandoahHeuristics::record_bytes_allocated(size_t bytes) {
 144   _bytes_allocated_since_CM = bytes;
 145   _bytes_allocated_start_CM = bytes;
 146   _allocation_rate_bytes.add(bytes);
 147 }
 148 
 149 void ShenandoahHeuristics::record_bytes_reclaimed(size_t bytes) {
 150   _bytes_reclaimed_this_cycle = bytes;
 151   _reclamation_rate_bytes.add(bytes);
 152 }
 153 
 154 void ShenandoahHeuristics::record_bytes_start_CM(size_t bytes) {
 155   _bytes_allocated_start_CM = bytes;
 156 }
 157 
 158 void ShenandoahHeuristics::record_bytes_end_CM(size_t bytes) {
 159   _bytes_allocated_during_CM = (bytes > _bytes_allocated_start_CM) ? (bytes - _bytes_allocated_start_CM)
 160                                                                    : bytes;
 161 }
 162 
 163 class AggressiveHeuristics : public ShenandoahHeuristics {
 164 public:
 165   AggressiveHeuristics() : ShenandoahHeuristics(){
 166   if (PrintGCDetails)
 167     tty->print_cr("Initializing aggressive heuristics");
 168   }
 169 
 170   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 171     return true;
 172   }
 173   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 174                                                ShenandoahHeapRegionSet* collection_set,
 175                                                ShenandoahHeapRegionSet* free_set) {
 176     region_set->set_garbage_threshold(8);
 177     region_set->choose_collection_and_free_sets(collection_set, free_set);
 178   }
 179 };
 180 
 181 class HalfwayHeuristics : public ShenandoahHeuristics {
 182 public:
 183   HalfwayHeuristics() : ShenandoahHeuristics() {
 184   if (PrintGCDetails)
 185     tty->print_cr("Initializing halfway heuristics");
 186   }
 187 
 188   bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 189     ShenandoahHeap* heap = ShenandoahHeap::heap();
 190     size_t threshold_bytes_allocated = heap->capacity() / 4;
 191     if (used * 2 > capacity && heap->_bytesAllocSinceCM > threshold_bytes_allocated)
 192       return true;
 193     else
 194       return false;
 195   }
 196   void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 197                                        ShenandoahHeapRegionSet* collection_set,
 198                                        ShenandoahHeapRegionSet* free_set) {
 199     region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes / 2);
 200     region_set->choose_collection_and_free_sets(collection_set, free_set);
 201   }
 202 };
 203 
 204 // GC as little as possible
 205 class LazyHeuristics : public ShenandoahHeuristics {
 206 public:
 207   LazyHeuristics() : ShenandoahHeuristics() {
 208     if (PrintGCDetails) {
 209       tty->print_cr("Initializing lazy heuristics");
 210     }
 211   }
 212 
 213   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 214     size_t targetStartMarking = (capacity / 5) * 4;
 215     if (used > targetStartMarking) {
 216       return true;
 217     } else {
 218       return false;
 219     }
 220   }
 221 
 222   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 223                                                ShenandoahHeapRegionSet* collection_set,
 224                                                ShenandoahHeapRegionSet* free_set) {
 225     region_set->choose_collection_and_free_sets(collection_set, free_set);
 226   }
 227 };
 228 
 229 // These are the heuristics in place when we made this class
 230 class StatusQuoHeuristics : public ShenandoahHeuristics {
 231 public:
 232   StatusQuoHeuristics() : ShenandoahHeuristics() {
 233     if (PrintGCDetails) {
 234       tty->print_cr("Initializing status quo heuristics");
 235     }
 236   }
 237 
 238   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 239     size_t targetStartMarking = capacity / 16;
 240     ShenandoahHeap* heap = ShenandoahHeap::heap();
 241     size_t threshold_bytes_allocated = heap->capacity() / 4;
 242 
 243     if (used > targetStartMarking
 244         && heap->_bytesAllocSinceCM > threshold_bytes_allocated) {
 245       // Need to check that an appropriate number of regions have
 246       // been allocated since last concurrent mark too.
 247       return true;
 248     } else {
 249       return false;
 250     }
 251   }
 252 
 253   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 254                                                ShenandoahHeapRegionSet* collection_set,
 255                                                ShenandoahHeapRegionSet* free_set) {
 256     region_set->choose_collection_and_free_sets(collection_set, free_set);
 257   }
 258 };
 259 
 260 static uintx clamp(uintx value, uintx min, uintx max) {
 261   value = MAX2(value, min);
 262   value = MIN2(value, max);
 263   return value;
 264 }
 265 
 266 static double get_percent(uintx value) {
 267   double _percent = static_cast<double>(clamp(value, 0, 100));
 268   return _percent / 100.;
 269 }
 270 
 271 class DynamicHeuristics : public ShenandoahHeuristics {
 272 private:
 273   double _free_threshold_factor;
 274   double _garbage_threshold_factor;
 275   double _allocation_threshold_factor;
 276 
 277   uintx _free_threshold;
 278   uintx _garbage_threshold;
 279   uintx _allocation_threshold;
 280 
 281 public:
 282   DynamicHeuristics() : ShenandoahHeuristics() {
 283     if (PrintGCDetails) {
 284       tty->print_cr("Initializing dynamic heuristics");
 285     }
 286 
 287     _free_threshold = 0;
 288     _garbage_threshold = 0;
 289     _allocation_threshold = 0;
 290 
 291     _free_threshold_factor = 0.;
 292     _garbage_threshold_factor = 0.;
 293     _allocation_threshold_factor = 0.;
 294   }
 295 
 296   virtual ~DynamicHeuristics() {}
 297 
 298   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 299 
 300     bool shouldStartConcurrentMark = false;
 301 
 302     ShenandoahHeap* heap = ShenandoahHeap::heap();
 303     size_t available = heap->free_regions()->available();
 304     uintx factor = heap->need_update_refs() ? ShenandoahFreeThreshold : ShenandoahInitialFreeThreshold;
 305     size_t targetStartMarking = (capacity * factor) / 100;
 306 
 307     size_t threshold_bytes_allocated = heap->capacity() * _allocation_threshold_factor;
 308     if (available < targetStartMarking &&
 309         heap->_bytesAllocSinceCM > threshold_bytes_allocated)
 310     {
 311       // Need to check that an appropriate number of regions have
 312       // been allocated since last concurrent mark too.
 313       shouldStartConcurrentMark = true;
 314     }
 315 
 316     if (shouldStartConcurrentMark && ShenandoahTracePhases) {
 317       tty->print_cr("Start GC at available: "SIZE_FORMAT", factor: "UINTX_FORMAT", update-refs: %s", available, factor, BOOL_TO_STR(heap->need_update_refs()));
 318     }
 319     return shouldStartConcurrentMark;
 320   }
 321 
 322   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 323                                                ShenandoahHeapRegionSet* collection_set,
 324                                                ShenandoahHeapRegionSet* free_set)
 325   {
 326     region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * _garbage_threshold_factor);
 327     region_set->choose_collection_and_free_sets(collection_set, free_set);
 328   }
 329 
 330   void set_free_threshold(uintx free_threshold) {
 331     this->_free_threshold_factor = get_percent(free_threshold);
 332     this->_free_threshold = free_threshold;
 333   }
 334 
 335   void set_garbage_threshold(uintx garbage_threshold) {
 336     this->_garbage_threshold_factor = get_percent(garbage_threshold);
 337     this->_garbage_threshold = garbage_threshold;
 338   }
 339 
 340   void set_allocation_threshold(uintx allocationThreshold) {
 341     this->_allocation_threshold_factor = get_percent(allocationThreshold);
 342     this->_allocation_threshold = allocationThreshold;
 343   }
 344 
 345   uintx get_allocation_threshold() {
 346     return this->_allocation_threshold;
 347   }
 348 
 349   uintx get_garbage_threshold() {
 350     return this->_garbage_threshold;
 351   }
 352 
 353   uintx get_free_threshold() {
 354     return this->_free_threshold;
 355   }
 356 };
 357 
 358 
 359 class AdaptiveHeuristics : public ShenandoahHeuristics {
 360 private:
 361   size_t _max_live_data;
 362   double _used_threshold_factor;
 363   double _garbage_threshold_factor;
 364   double _allocation_threshold_factor;
 365 
 366   uintx _used_threshold;
 367   uintx _garbage_threshold;
 368   uintx _allocation_threshold;
 369 
 370 public:
 371   AdaptiveHeuristics() : ShenandoahHeuristics() {
 372     if (PrintGCDetails) {
 373       tty->print_cr("Initializing dynamic heuristics");
 374     }
 375 
 376     _max_live_data = 0;
 377 
 378     _used_threshold = 0;
 379     _garbage_threshold = 0;
 380     _allocation_threshold = 0;
 381 
 382     _used_threshold_factor = 0.;
 383     _garbage_threshold_factor = 0.1;
 384     _allocation_threshold_factor = 0.;
 385   }
 386 
 387   virtual ~AdaptiveHeuristics() {}
 388 
 389   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const {
 390 
 391     ShenandoahHeap* _heap = ShenandoahHeap::heap();
 392     bool shouldStartConcurrentMark = false;
 393 
 394     size_t max_live_data = _max_live_data;
 395     if (max_live_data == 0) {
 396       max_live_data = capacity * 0.2; // Very generous initial value.
 397     } else {
 398       max_live_data *= 1.3; // Add some wiggle room.
 399     }
 400     size_t max_cycle_allocated = _heap->_max_allocated_gc;
 401     if (max_cycle_allocated == 0) {
 402       max_cycle_allocated = capacity * 0.3; // Very generous.
 403     } else {
 404       max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough.
 405     }
 406     size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data;
 407     if (used > threshold)
 408     {
 409       shouldStartConcurrentMark = true;
 410     }
 411 
 412     return shouldStartConcurrentMark;
 413   }
 414 
 415   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 416                                                ShenandoahHeapRegionSet* collection_set,
 417                                                ShenandoahHeapRegionSet* free_set)
 418   {
 419     size_t bytes_alloc = ShenandoahHeap::heap()->_bytesAllocSinceCM;
 420     size_t min_garbage =  bytes_alloc/* * 1.1*/;
 421     region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * _garbage_threshold_factor);
 422     region_set->choose_collection_and_free_sets_min_garbage(collection_set, free_set, min_garbage);
 423     /*
 424     tty->print_cr("garbage to be collected: "SIZE_FORMAT, collection_set->garbage());
 425     tty->print_cr("objects to be evacuated: "SIZE_FORMAT, collection_set->live_data());
 426     */
 427     _max_live_data = MAX2(_max_live_data, collection_set->live_data());
 428   }
 429 
 430   void set_used_threshold(uintx used_threshold) {
 431     this->_used_threshold_factor = get_percent(used_threshold);
 432     this->_used_threshold = used_threshold;
 433   }
 434 
 435   void set_garbage_threshold(uintx garbage_threshold) {
 436     this->_garbage_threshold_factor = get_percent(garbage_threshold);
 437     this->_garbage_threshold = garbage_threshold;
 438   }
 439 
 440   void set_allocation_threshold(uintx allocationThreshold) {
 441     this->_allocation_threshold_factor = get_percent(allocationThreshold);
 442     this->_allocation_threshold = allocationThreshold;
 443   }
 444 
 445   uintx get_allocation_threshold() {
 446     return this->_allocation_threshold;
 447   }
 448 
 449   uintx get_garbage_threshold() {
 450     return this->_garbage_threshold;
 451   }
 452 
 453   uintx get_used_threshold() {
 454     return this->_used_threshold;
 455   }
 456 };
 457 
 458 class NewAdaptiveHeuristics : public ShenandoahHeuristics {
 459 private:
 460   size_t _max_live_data;
 461   double _target_heap_occupancy_factor;
 462   double _allocation_threshold_factor;
 463   size_t _last_bytesAllocSinceCM;
 464 
 465   uintx _target_heap_occupancy;
 466   uintx _allocation_threshold;
 467 
 468 public:
 469   NewAdaptiveHeuristics() : ShenandoahHeuristics()
 470   {
 471     if (PrintGCDetails) {
 472       tty->print_cr("Initializing newadaptive heuristics");
 473     }
 474     _max_live_data = 0;
 475     _allocation_threshold = 0;
 476     _target_heap_occupancy_factor = 0.;
 477     _allocation_threshold_factor = 0.;
 478     _last_bytesAllocSinceCM = 0;
 479   }
 480 
 481   virtual ~NewAdaptiveHeuristics() {}
 482 
 483   virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const
 484   {
 485       if (this->_bytes_allocated_during_CM > 0) {
 486           // Not the first concurrent mark.
 487           // _bytes_allocated_during_CM
 488           ShenandoahHeap *heap = ShenandoahHeap::heap();
 489           size_t threshold_bytes_allocated = heap->capacity() / 4;
 490           size_t targetStartMarking = (size_t) capacity * this->_target_heap_occupancy_factor;
 491           return (used > targetStartMarking) && (this->_bytes_allocated_during_CM > threshold_bytes_allocated);
 492       } else {
 493           // First concurrent mark.
 494           size_t targetStartMarking = capacity / 2;
 495           ShenandoahHeap *heap = ShenandoahHeap::heap();
 496           size_t threshold_bytes_allocated = heap->capacity() / 4;
 497 
 498           // Need to check that an appropriate number of regions have
 499           // been allocated since last concurrent mark too.
 500           return (used > targetStartMarking) && (heap->_bytesAllocSinceCM > threshold_bytes_allocated);
 501       }
 502   }
 503 
 504   virtual void choose_collection_and_free_sets(ShenandoahHeapRegionSet* region_set,
 505                                                ShenandoahHeapRegionSet* collection_set,
 506                                                ShenandoahHeapRegionSet* free_set)
 507   {
 508     ShenandoahHeap *_heap = ShenandoahHeap::heap();
 509     this->_last_bytesAllocSinceCM = ShenandoahHeap::heap()->_bytesAllocSinceCM;
 510     if (this->_last_bytesAllocSinceCM > 0) {
 511       size_t min_garbage = this->_last_bytesAllocSinceCM;
 512       region_set->choose_collection_and_free_sets_min_garbage(collection_set, free_set, min_garbage);
 513     } else {
 514       region_set->set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes / 2);
 515       region_set->choose_collection_and_free_sets(collection_set, free_set);
 516     }
 517     this->_max_live_data = MAX2(this->_max_live_data, collection_set->live_data());
 518   }
 519 
 520   void set_target_heap_occupancy(uintx target_heap_occupancy) {
 521     this->_target_heap_occupancy_factor = get_percent(target_heap_occupancy);
 522     this->_target_heap_occupancy = target_heap_occupancy;
 523   }
 524 
 525   void set_allocation_threshold(uintx allocationThreshold) {
 526     this->_allocation_threshold_factor = get_percent(allocationThreshold);
 527     this->_allocation_threshold = allocationThreshold;
 528   }
 529 
 530   uintx get_allocation_threshold() {
 531     return this->_allocation_threshold;
 532   }
 533 
 534   uintx get_target_heap_occupancy() {
 535     return this->_target_heap_occupancy;
 536   }
 537 };
 538 
 539 
 540 static DynamicHeuristics *configureDynamicHeuristics() {
 541   DynamicHeuristics *heuristics = new DynamicHeuristics();
 542 
 543   heuristics->set_garbage_threshold(ShenandoahGarbageThreshold);
 544   heuristics->set_allocation_threshold(ShenandoahAllocationThreshold);
 545   heuristics->set_free_threshold(ShenandoahFreeThreshold);
 546   if (ShenandoahLogConfig) {
 547     tty->print_cr("Shenandoah dynamic heuristics thresholds: allocation "SIZE_FORMAT", used "SIZE_FORMAT", garbage "SIZE_FORMAT,
 548                   heuristics->get_allocation_threshold(),
 549                   heuristics->get_free_threshold(),
 550                   heuristics->get_garbage_threshold());
 551   }
 552   return heuristics;
 553 }
 554 
 555 
 556 static NewAdaptiveHeuristics* configureNewAdaptiveHeuristics() {
 557   NewAdaptiveHeuristics* heuristics = new NewAdaptiveHeuristics();
 558 
 559   heuristics->set_target_heap_occupancy(ShenandoahTargetHeapOccupancy);
 560   if (ShenandoahLogConfig) {
 561     tty->print_cr( "Shenandoah newadaptive heuristics target heap occupancy: "SIZE_FORMAT,
 562                    heuristics->get_target_heap_occupancy() );
 563   }
 564   return heuristics;
 565 }
 566 
 567 
 568 ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() {
 569 
 570   ShenandoahHeapRegion::setup_heap_region_size(initial_heap_byte_size(), initial_heap_byte_size());
 571 
 572   initialize_all();
 573 
 574   _tracer = new (ResourceObj::C_HEAP, mtGC) ShenandoahTracer();
 575   _stw_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
 576   _conc_timer = new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer();
 577   _user_requested_gcs = 0;
 578   _allocation_failure_gcs = 0;
 579   _conc_gc_aborted = false;
 580 
 581   _phase_names[init_mark] = "InitMark";
 582   _phase_names[final_mark] = "FinalMark";
 583   _phase_names[rescan_roots] = "RescanRoots";
 584   _phase_names[drain_satb] = "DrainSATB";
 585   _phase_names[drain_queues] = "DrainQueues";
 586   _phase_names[weakrefs] = "WeakRefs";
 587   _phase_names[prepare_evac] = "PrepareEvac";
 588   _phase_names[init_evac] = "InitEvac";
 589   _phase_names[final_evac] = "FinalEvacuation";
 590   _phase_names[final_uprefs] = "FinalUpdateRefs";
 591 
 592   _phase_names[update_roots] = "UpdateRoots";
 593   _phase_names[recycle_regions] = "RecycleRegions";
 594   _phase_names[reset_bitmaps] = "ResetBitmaps";
 595   _phase_names[resize_tlabs] = "ResizeTLABs";
 596 
 597   _phase_names[full_gc] = "FullGC";
 598   _phase_names[conc_mark] = "ConcurrentMark";
 599   _phase_names[conc_evac] = "ConcurrentEvacuation";
 600   _phase_names[conc_uprefs] = "ConcurrentUpdateReferences";
 601 
 602   if (ShenandoahGCHeuristics != NULL) {
 603     if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) {
 604       if (ShenandoahLogConfig) {
 605         tty->print_cr("Shenandoah heuristics: aggressive");
 606       }
 607       _heuristics = new AggressiveHeuristics();
 608     } else if (strcmp(ShenandoahGCHeuristics, "statusquo") == 0) {
 609       if (ShenandoahLogConfig) {
 610         tty->print_cr("Shenandoah heuristics: statusquo");
 611       }
 612       _heuristics = new StatusQuoHeuristics();
 613     } else if (strcmp(ShenandoahGCHeuristics, "halfway") == 0) {
 614       if (ShenandoahLogConfig) {
 615         tty->print_cr("Shenandoah heuristics: halfway");
 616       }
 617       _heuristics = new HalfwayHeuristics();
 618     } else if (strcmp(ShenandoahGCHeuristics, "lazy") == 0) {
 619       if (ShenandoahLogConfig) {
 620         tty->print_cr("Shenandoah heuristics: lazy");
 621       }
 622       _heuristics = new LazyHeuristics();
 623     } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) {
 624       if (ShenandoahLogConfig) {
 625         tty->print_cr("Shenandoah heuristics: dynamic");
 626       }
 627       _heuristics = configureDynamicHeuristics();
 628     } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) {
 629       if (ShenandoahLogConfig) {
 630         tty->print_cr("Shenandoah heuristics: adaptive");
 631       }
 632       _heuristics = new AdaptiveHeuristics();
 633     } else if (strcmp(ShenandoahGCHeuristics, "newadaptive") == 0) {
 634       if (ShenandoahLogConfig) {
 635         tty->print_cr("Shenandoah heuristics: newadaptive");
 636       }
 637       _heuristics = configureNewAdaptiveHeuristics();
 638     } else {
 639       fatal("Unknown -XX:ShenandoahGCHeuristics option");
 640     }
 641   } else {
 642       if (ShenandoahLogConfig) {
 643         tty->print_cr("Shenandoah heuristics: statusquo (default)");
 644       }
 645     _heuristics = new StatusQuoHeuristics();
 646   }
 647 
 648 }
 649 
 650 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() {
 651   return this;
 652 }
 653 
 654 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() {
 655   return BarrierSet::ShenandoahBarrierSet;
 656 }
 657 
 658 HeapWord* ShenandoahCollectorPolicy::mem_allocate_work(size_t size,
 659                                                        bool is_tlab,
 660                                                        bool* gc_overhead_limit_was_exceeded) {
 661   guarantee(false, "Not using this policy feature yet.");
 662   return NULL;
 663 }
 664 
 665 HeapWord* ShenandoahCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) {
 666   guarantee(false, "Not using this policy feature yet.");
 667   return NULL;
 668 }
 669 
 670 void ShenandoahCollectorPolicy::initialize_alignments() {
 671 
 672   // This is expected by our algorithm for ShenandoahHeap::heap_region_containing().
 673   _space_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 674   _heap_alignment = ShenandoahHeapRegion::RegionSizeBytes;
 675 }
 676 
 677 void ShenandoahCollectorPolicy::post_heap_initialize() {
 678   // Nothing to do here (yet).
 679 }
 680 
 681 void ShenandoahCollectorPolicy::record_bytes_allocated(size_t bytes) {
 682   _heuristics->record_bytes_allocated(bytes);
 683 }
 684 
 685 void ShenandoahCollectorPolicy::record_bytes_start_CM(size_t bytes) {
 686   _heuristics->record_bytes_start_CM(bytes);
 687 }
 688 
 689 void ShenandoahCollectorPolicy::record_bytes_end_CM(size_t bytes) {
 690   _heuristics->record_bytes_end_CM(bytes);
 691 }
 692 
 693 void ShenandoahCollectorPolicy::record_bytes_reclaimed(size_t bytes) {
 694   _heuristics->record_bytes_reclaimed(bytes);
 695 }
 696 
 697 void ShenandoahCollectorPolicy::record_user_requested_gc() {
 698   _user_requested_gcs++;
 699 }
 700 
 701 void ShenandoahCollectorPolicy::record_allocation_failure_gc() {
 702   _allocation_failure_gcs++;
 703 }
 704 
 705 bool ShenandoahCollectorPolicy::should_start_concurrent_mark(size_t used,
 706                                                              size_t capacity) {
 707   ShenandoahHeap* heap = ShenandoahHeap::heap();
 708   return _heuristics->should_start_concurrent_mark(used, capacity);
 709 }
 710 
 711 bool ShenandoahCollectorPolicy::update_refs_early() {
 712   return _heuristics->update_refs_early();
 713 }
 714 
 715 void ShenandoahCollectorPolicy::choose_collection_and_free_sets(
 716                              ShenandoahHeapRegionSet* region_set,
 717                              ShenandoahHeapRegionSet* collection_set,
 718                              ShenandoahHeapRegionSet* free_set) {
 719   _heuristics->choose_collection_and_free_sets(region_set, collection_set, free_set);
 720 }
 721 
 722 void ShenandoahCollectorPolicy::print_tracing_info() {
 723   print_summary_sd("Initial Mark Pauses", 0, &(_timing_data[init_mark]._ms));
 724   print_summary_sd("Final Mark Pauses", 0, &(_timing_data[final_mark]._ms));
 725 
 726   print_summary_sd("Rescan Roots", 2, &(_timing_data[rescan_roots]._ms));
 727   print_summary_sd("Drain SATB", 2, &(_timing_data[drain_satb]._ms));
 728   print_summary_sd("Drain Queues", 2, &(_timing_data[drain_queues]._ms));
 729   if (ShenandoahProcessReferences) {
 730     print_summary_sd("Weak References", 2, &(_timing_data[weakrefs]._ms));
 731   }
 732   print_summary_sd("Prepare Evacuation", 2, &(_timing_data[prepare_evac]._ms));
 733   print_summary_sd("Initial Evacuation", 2, &(_timing_data[init_evac]._ms));
 734 
 735   print_summary_sd("Final Evacuation Pauses", 0, &(_timing_data[final_evac]._ms));
 736   print_summary_sd("Final Update Refs Pauses", 0, &(_timing_data[final_uprefs]._ms));
 737   print_summary_sd("Update roots", 2, &(_timing_data[update_roots]._ms));
 738   print_summary_sd("Recycle regions", 2, &(_timing_data[recycle_regions]._ms));
 739   print_summary_sd("Reset bitmaps", 2, &(_timing_data[reset_bitmaps]._ms));
 740   print_summary_sd("Resize TLABs", 2, &(_timing_data[resize_tlabs]._ms));
 741   gclog_or_tty->print_cr(" ");
 742   print_summary_sd("Concurrent Marking Times", 0, &(_timing_data[conc_mark]._ms));
 743   print_summary_sd("Concurrent Evacuation Times", 0, &(_timing_data[conc_evac]._ms));
 744   print_summary_sd("Concurrent Update References Times", 0, &(_timing_data[conc_uprefs]._ms));
 745   print_summary_sd("Full GC Times", 0, &(_timing_data[full_gc]._ms));
 746 
 747   gclog_or_tty->print_cr("User requested GCs: "SIZE_FORMAT, _user_requested_gcs);
 748   gclog_or_tty->print_cr("Allocation failure GCs: "SIZE_FORMAT, _allocation_failure_gcs);
 749 
 750   gclog_or_tty->print_cr(" ");
 751   double total_sum = _timing_data[init_mark]._ms.sum() +
 752     _timing_data[final_mark]._ms.sum() +
 753     _timing_data[final_evac]._ms.sum() +
 754     _timing_data[final_uprefs]._ms.sum();
 755   double total_avg = (_timing_data[init_mark]._ms.avg() +
 756                       _timing_data[final_mark]._ms.avg() +
 757                       _timing_data[final_evac]._ms.avg() +
 758                       _timing_data[final_uprefs]._ms.avg()) / 4.0;
 759   double total_max = MAX2(
 760                           MAX2(
 761                                MAX2(_timing_data[init_mark]._ms.maximum(),
 762                                     _timing_data[final_mark]._ms.maximum()),
 763                                _timing_data[final_evac]._ms.maximum()),
 764                           _timing_data[final_uprefs]._ms.maximum());
 765 
 766   gclog_or_tty->print_cr("%-27s = %8.2lf s, avg = %8.2lf ms, max = %8.2lf ms",
 767                          "Total", total_sum / 1000.0, total_avg, total_max);
 768 
 769 }
 770 
 771 void ShenandoahCollectorPolicy::print_summary_sd(const char* str, uint indent, const NumberSeq* seq)  {
 772   double sum = seq->sum();
 773   for (uint i = 0; i < indent; i++) gclog_or_tty->print(" ");
 774   gclog_or_tty->print_cr("%-27s = %8.2lf s (avg = %8.2lf ms)",
 775                          str, sum / 1000.0, seq->avg());
 776   for (uint i = 0; i < indent; i++) gclog_or_tty->print(" ");
 777   gclog_or_tty->print_cr("%s = "INT32_FORMAT_W(5)", std dev = %8.2lf ms, max = %8.2lf ms)",
 778                          "(num", seq->num(), seq->sd(), seq->maximum());
 779 }