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 }