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 }