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 ShenandoahHeap* heap = ShenandoahHeap::heap(); 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 127 " and live = " SIZE_FORMAT " and _garbage_threshold = " SIZE_FORMAT "\n", 128 region->region_number(), region->garbage(), region->get_live_data(), _garbage_threshold); 129 130 assert(! region->is_humongous(), "no humongous regions in collection set"); 131 132 if (region->get_live_data() == 0) { 133 // We can recycle it right away and put it in the free set. 134 heap->decrease_used(region->used()); 135 region->recycle(); 136 } else { 137 collection_set->add_region(region); 138 region->set_in_collection_set(true); 139 } 140 } else { 141 log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 142 " and live = " SIZE_FORMAT " and _garbage_threshold = " SIZE_FORMAT "\n", 143 region->region_number(), region->garbage(), region->get_live_data(), _garbage_threshold); 144 } 145 } 146 147 } 148 149 void ShenandoahHeuristics::choose_collection_set_min_garbage(ShenandoahCollectionSet* collection_set, size_t min_garbage) { 150 ShenandoahHeapRegionSet* sorted_regions = ShenandoahHeap::heap()->sorted_regions(); 151 sorted_regions->sort(compareHeapRegionsByGarbage); 152 size_t i = 0; 153 size_t end = sorted_regions->active_regions(); 154 155 size_t garbage = 0; 156 while (i < end && garbage < min_garbage) { 157 ShenandoahHeapRegion* region = sorted_regions->get(i++); 158 if (region->garbage() > _garbage_threshold && ! region->is_humongous() && ! region->is_pinned()) { 159 collection_set->add_region(region); 160 garbage += region->garbage(); 161 region->set_in_collection_set(true); 162 } 163 } 164 } 165 166 void ShenandoahHeuristics::choose_free_set(ShenandoahFreeSet* free_set) { 167 168 ShenandoahHeapRegionSet* ordered_regions = ShenandoahHeap::heap()->regions(); 169 size_t i = 0; 170 size_t end = ordered_regions->active_regions(); 171 172 ShenandoahHeap* heap = ShenandoahHeap::heap(); 173 while (i < end) { 174 ShenandoahHeapRegion* region = ordered_regions->get(i++); 175 if ((! heap->in_collection_set(region)) 176 && (! region->is_humongous()) 177 && (! region->is_pinned())) { 178 free_set->add_region(region); 179 } 180 } 181 } 182 183 void ShenandoahCollectorPolicy::record_workers_start(TimingPhase phase) { 216 _allocation_rate_bytes.add(bytes); 217 } 218 219 void ShenandoahHeuristics::record_bytes_reclaimed(size_t bytes) { 220 _bytes_reclaimed_this_cycle = bytes; 221 _reclamation_rate_bytes.add(bytes); 222 } 223 224 void ShenandoahHeuristics::record_bytes_start_CM(size_t bytes) { 225 _bytes_allocated_start_CM = bytes; 226 } 227 228 void ShenandoahHeuristics::record_bytes_end_CM(size_t bytes) { 229 _bytes_allocated_during_CM = (bytes > _bytes_allocated_start_CM) ? (bytes - _bytes_allocated_start_CM) 230 : bytes; 231 } 232 233 class PassiveHeuristics : public ShenandoahHeuristics { 234 public: 235 PassiveHeuristics() : ShenandoahHeuristics() { 236 set_garbage_threshold(8); 237 } 238 239 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 240 // Never do concurrent GCs. 241 return false; 242 } 243 244 virtual bool process_references() { 245 // Randomly process refs with 50% chance. 246 return (os::random() & 1) == 1; 247 } 248 249 virtual bool unload_classes() { 250 // Randomly unload classes with 50% chance. 251 return (os::random() & 1) == 1; 252 } 253 }; 254 255 class AggressiveHeuristics : public ShenandoahHeuristics { 256 public: 257 AggressiveHeuristics() : ShenandoahHeuristics() { 258 set_garbage_threshold(8); 259 } 260 261 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 262 return true; 263 } 264 265 virtual bool process_references() { 266 // Randomly process refs with 50% chance. 267 return (os::random() & 1) == 1; 268 } 269 270 virtual bool unload_classes() { 271 // Randomly unload classes with 50% chance. 272 return (os::random() & 1) == 1; 273 } 274 }; 275 276 class DynamicHeuristics : public ShenandoahHeuristics { 277 public: 278 DynamicHeuristics() : ShenandoahHeuristics() { 279 log_info(gc, init)("Shenandoah dynamic heuristics thresholds: allocation "SIZE_FORMAT", free "SIZE_FORMAT", garbage "SIZE_FORMAT, 280 ShenandoahAllocationThreshold, 281 ShenandoahFreeThreshold, 282 ShenandoahGarbageThreshold); 283 } 284 285 virtual ~DynamicHeuristics() {} 286 287 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 288 289 bool shouldStartConcurrentMark = false; 290 291 ShenandoahHeap* heap = ShenandoahHeap::heap(); 292 size_t free_capacity = heap->free_regions()->capacity(); 293 size_t free_used = heap->free_regions()->used(); 294 assert(free_used <= free_capacity, "must use less than capacity"); 295 size_t available = free_capacity - free_used; 296 uintx factor = heap->need_update_refs() ? ShenandoahFreeThreshold : ShenandoahInitialFreeThreshold; 297 size_t targetStartMarking = (capacity * factor) / 100; 298 299 size_t threshold_bytes_allocated = heap->capacity() * ShenandoahAllocationThreshold / 100; 300 if (available < targetStartMarking && 301 heap->bytes_allocated_since_cm() > threshold_bytes_allocated) 302 { 303 // Need to check that an appropriate number of regions have 304 // been allocated since last concurrent mark too. 305 shouldStartConcurrentMark = true; 306 } 307 308 return shouldStartConcurrentMark; 309 } 310 311 virtual void choose_collection_set(ShenandoahCollectionSet* collection_set) { 312 set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100); 313 ShenandoahHeuristics::choose_collection_set(collection_set); 314 } 315 }; 316 317 318 class AdaptiveHeuristics : public ShenandoahHeuristics { 319 private: 320 size_t _max_live_data; 321 double _used_threshold_factor; 322 double _garbage_threshold_factor; 323 double _allocation_threshold_factor; 324 325 uintx _used_threshold; 326 uintx _garbage_threshold; 327 uintx _allocation_threshold; 328 329 public: 330 AdaptiveHeuristics() : ShenandoahHeuristics() { 331 _max_live_data = 0; 332 333 _used_threshold = 0; 334 _garbage_threshold = 0; 335 _allocation_threshold = 0; 336 337 _used_threshold_factor = 0.; 338 _garbage_threshold_factor = 0.1; 339 _allocation_threshold_factor = 0.; 340 } 341 342 virtual ~AdaptiveHeuristics() {} 343 344 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 345 346 ShenandoahHeap* _heap = ShenandoahHeap::heap(); 347 bool shouldStartConcurrentMark = false; 348 OrderAccess::release(); 349 350 size_t max_live_data = _max_live_data; 351 if (max_live_data == 0) { 352 max_live_data = capacity * 0.2; // Very generous initial value. 353 } else { 354 max_live_data *= 1.3; // Add some wiggle room. 355 } 356 size_t max_cycle_allocated = _heap->max_allocated_gc(); 357 if (max_cycle_allocated == 0) { 358 max_cycle_allocated = capacity * 0.3; // Very generous. 359 } else { 360 max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough. 361 } 362 size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data; 363 if (used > threshold) 364 { 365 shouldStartConcurrentMark = true; 366 } 367 368 return shouldStartConcurrentMark; 369 } 370 371 virtual void choose_collection_set(ShenandoahCollectionSet* collection_set) { 372 size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm(); 373 size_t min_garbage = bytes_alloc/* * 1.1*/; 374 set_garbage_threshold(ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100); 375 ShenandoahHeuristics::choose_collection_set_min_garbage(collection_set, min_garbage); 376 377 log_develop_trace(gc)("Garbage to be collected: "SIZE_FORMAT, collection_set->garbage()); 378 log_develop_trace(gc)("Objects to be evacuated: "SIZE_FORMAT, collection_set->live_data()); 379 380 _max_live_data = MAX2(_max_live_data, collection_set->live_data()); 381 } 382 }; 383 384 ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() : _cycle_counter(0) { 385 386 ShenandoahHeapRegion::setup_heap_region_size(initial_heap_byte_size(), max_heap_byte_size()); 387 388 initialize_all(); 389 390 _tracer = new (ResourceObj::C_HEAP, mtGC) ShenandoahTracer(); 391 _stw_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer(); 392 _conc_timer = new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer(); 393 _user_requested_gcs = 0; 394 _allocation_failure_gcs = 0; 395 _conc_gc_aborted = false; 396 397 _phase_names[init_mark] = "Initial Mark Pauses (net)"; 398 _phase_names[init_mark_gross] = "Initial Mark Pauses (gross)"; 399 _phase_names[final_mark] = "Final Mark Pauses (net)"; 400 _phase_names[final_mark_gross] = "Final Mark Pauses (gross)"; 454 455 _phase_names[full_gc] = "Full GC Times"; 456 _phase_names[full_gc_mark] = " Mark"; 457 _phase_names[full_gc_mark_drain_queues] = " Drain Queues"; 458 _phase_names[full_gc_mark_weakrefs] = " Weak References"; 459 _phase_names[full_gc_mark_class_unloading] = " Class Unloading"; 460 _phase_names[full_gc_calculate_addresses] = " Calculate Addresses"; 461 _phase_names[full_gc_adjust_pointers] = " Adjust Pointers"; 462 _phase_names[full_gc_copy_objects] = " Copy Objects"; 463 464 _phase_names[conc_mark] = "Concurrent Marking Times"; 465 _phase_names[conc_evac] = "Concurrent Evacuation Times"; 466 467 if (ShenandoahGCHeuristics != NULL) { 468 if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { 469 log_info(gc, init)("Shenandoah heuristics: aggressive"); 470 _heuristics = new AggressiveHeuristics(); 471 } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) { 472 log_info(gc, init)("Shenandoah heuristics: dynamic"); 473 _heuristics = new DynamicHeuristics(); 474 } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { 475 log_info(gc, init)("Shenandoah heuristics: adaptive"); 476 _heuristics = new AdaptiveHeuristics(); 477 } else if (strcmp(ShenandoahGCHeuristics, "passive") == 0) { 478 log_info(gc, init)("Shenandoah heuristics: passive"); 479 _heuristics = new PassiveHeuristics(); 480 } else { 481 vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option"); 482 } 483 } else { 484 ShouldNotReachHere(); 485 } 486 _phase_times = new ShenandoahPhaseTimes(MAX2(ConcGCThreads, ParallelGCThreads)); 487 } 488 489 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() { 490 return this; 491 } 492 493 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() { | 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 class ShenandoahHeuristics : public CHeapObj<mtGC> { 32 33 NumberSeq _allocation_rate_bytes; 34 NumberSeq _reclamation_rate_bytes; 35 36 size_t _bytes_allocated_since_CM; 37 size_t _bytes_reclaimed_this_cycle; 38 39 protected: 40 size_t _bytes_allocated_start_CM; 41 size_t _bytes_allocated_during_CM; 42 43 public: 44 45 ShenandoahHeuristics(); 46 47 void record_bytes_allocated(size_t bytes); 48 void record_bytes_reclaimed(size_t bytes); 49 void record_bytes_start_CM(size_t bytes); 50 void record_bytes_end_CM(size_t bytes); 51 52 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const=0; 53 54 virtual void start_choose_collection_set() { 55 } 56 virtual void end_choose_collection_set() { 57 } 58 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) = 0; 59 60 void choose_collection_set(ShenandoahCollectionSet* collection_set); 61 62 virtual void choose_free_set(ShenandoahFreeSet* free_set); 63 64 virtual bool process_references() { 65 if (ShenandoahRefProcFrequency == 0) return false; 66 size_t cycle = ShenandoahHeap::heap()->shenandoahPolicy()->cycle_counter(); 67 // Process references every Nth GC cycle. 68 return cycle % ShenandoahRefProcFrequency == 0; 69 } 70 71 virtual bool unload_classes() { 72 if (ShenandoahUnloadClassesFrequency == 0) return false; 73 size_t cycle = ShenandoahHeap::heap()->shenandoahPolicy()->cycle_counter(); 74 // Process references every Nth GC cycle. 75 return cycle % ShenandoahUnloadClassesFrequency == 0; 76 } 77 78 private: 79 static int compareHeapRegionsByGarbage(ShenandoahHeapRegion* a, ShenandoahHeapRegion* b); 80 81 }; 82 83 ShenandoahHeuristics::ShenandoahHeuristics() : 84 _bytes_allocated_since_CM(0), 85 _bytes_reclaimed_this_cycle(0), 86 _bytes_allocated_start_CM(0), 87 _bytes_allocated_during_CM(0) 88 { 89 } 90 91 int ShenandoahHeuristics::compareHeapRegionsByGarbage(ShenandoahHeapRegion* a, ShenandoahHeapRegion* b) { 92 if (a == NULL) { 93 if (b == NULL) { 94 return 0; 95 } else { 96 return 1; 97 } 98 } else if (b == NULL) { 99 return -1; 100 } 101 102 size_t garbage_a = a->garbage(); 103 size_t garbage_b = b->garbage(); 104 105 if (garbage_a > garbage_b) 106 return -1; 107 else if (garbage_a < garbage_b) 108 return 1; 109 else return 0; 110 } 111 112 void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { 113 ShenandoahHeapRegionSet* sorted_regions = ShenandoahHeap::heap()->sorted_regions(); 114 sorted_regions->sort(compareHeapRegionsByGarbage); 115 116 start_choose_collection_set(); 117 118 size_t i = 0; 119 size_t end = sorted_regions->active_regions(); 120 ShenandoahHeap* heap = ShenandoahHeap::heap(); 121 size_t total_garbage = heap->garbage(); 122 size_t immediate_garbage = 0; 123 size_t immediate_regions = 0; 124 for (size_t i = 0; i < end; i++) { 125 ShenandoahHeapRegion* region = sorted_regions->get(i); 126 127 if (! region->is_humongous() && ! region->is_pinned()) { 128 if ((! region->is_empty()) && region->get_live_data() == 0) { 129 // We can recycle it right away and put it in the free set. 130 immediate_regions++; 131 immediate_garbage += region->garbage(); 132 heap->decrease_used(region->used()); 133 region->recycle(); 134 log_develop_trace(gc)("Choose region for immediate" SIZE_FORMAT " with garbage = " SIZE_FORMAT 135 " and live = " SIZE_FORMAT "\n", 136 region->region_number(), region->garbage(), region->get_live_data()); 137 } else if (region_in_collection_set(region, immediate_garbage)) { 138 log_develop_trace(gc)("Choose region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 139 " and live = " SIZE_FORMAT "\n", 140 region->region_number(), region->garbage(), region->get_live_data()); 141 collection_set->add_region(region); 142 region->set_in_collection_set(true); 143 } 144 } else { 145 assert(region->get_live_data() != 0 || region->is_empty() || region->is_pinned() || region->is_humongous(), "check rejected"); 146 log_develop_trace(gc)("Rejected region " SIZE_FORMAT " with garbage = " SIZE_FORMAT 147 " and live = " SIZE_FORMAT "\n", 148 region->region_number(), region->garbage(), region->get_live_data()); 149 } 150 } 151 152 end_choose_collection_set(); 153 154 log_debug(gc)("Total Garbage: "SIZE_FORMAT, total_garbage); 155 log_debug(gc)("Immediate Garbage: "SIZE_FORMAT, immediate_garbage); 156 log_debug(gc)("Immediate Garbage regions: "SIZE_FORMAT, immediate_regions); 157 log_debug(gc)("Garbage to be collected: "SIZE_FORMAT, collection_set->garbage()); 158 log_debug(gc)("Objects to be evacuated: "SIZE_FORMAT, collection_set->live_data()); 159 log_debug(gc)("Live / Garbage ratio: "SIZE_FORMAT"%%", collection_set->live_data() * 100 / MAX2(collection_set->garbage(), 1UL)); 160 log_debug(gc)("Collected-Garbage ratio / Total-garbage: "SIZE_FORMAT"%%", collection_set->garbage() * 100 / MAX2(total_garbage, 1UL)); 161 } 162 163 void ShenandoahHeuristics::choose_free_set(ShenandoahFreeSet* free_set) { 164 165 ShenandoahHeapRegionSet* ordered_regions = ShenandoahHeap::heap()->regions(); 166 size_t i = 0; 167 size_t end = ordered_regions->active_regions(); 168 169 ShenandoahHeap* heap = ShenandoahHeap::heap(); 170 while (i < end) { 171 ShenandoahHeapRegion* region = ordered_regions->get(i++); 172 if ((! heap->in_collection_set(region)) 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) { 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 } 234 235 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 236 return r->garbage() > 0; 237 } 238 239 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 240 // Never do concurrent GCs. 241 return false; 242 } 243 244 virtual bool process_references() { 245 // Randomly process refs with 50% chance. 246 return (os::random() & 1) == 1; 247 } 248 249 virtual bool unload_classes() { 250 // Randomly unload classes with 50% chance. 251 return (os::random() & 1) == 1; 252 } 253 }; 254 255 class AggressiveHeuristics : public ShenandoahHeuristics { 256 public: 257 AggressiveHeuristics() : ShenandoahHeuristics() { 258 } 259 260 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 261 return r->garbage() > 0; 262 } 263 264 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 265 return true; 266 } 267 268 virtual bool process_references() { 269 // Randomly process refs with 50% chance. 270 return (os::random() & 1) == 1; 271 } 272 273 virtual bool unload_classes() { 274 // Randomly unload classes with 50% chance. 275 return (os::random() & 1) == 1; 276 } 277 }; 278 279 class DynamicHeuristics : public ShenandoahHeuristics { 280 public: 281 DynamicHeuristics() : ShenandoahHeuristics() { 282 log_info(gc, init)("Shenandoah heuristics thresholds: allocation "SIZE_FORMAT", free "SIZE_FORMAT", garbage "SIZE_FORMAT, 283 ShenandoahAllocationThreshold, 284 ShenandoahFreeThreshold, 285 ShenandoahGarbageThreshold); 286 } 287 288 virtual ~DynamicHeuristics() {} 289 290 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 291 292 bool shouldStartConcurrentMark = false; 293 294 ShenandoahHeap* heap = ShenandoahHeap::heap(); 295 size_t free_capacity = heap->free_regions()->capacity(); 296 size_t free_used = heap->free_regions()->used(); 297 assert(free_used <= free_capacity, "must use less than capacity"); 298 size_t available = free_capacity - free_used; 299 uintx factor = heap->need_update_refs() ? ShenandoahFreeThreshold : ShenandoahInitialFreeThreshold; 300 size_t targetStartMarking = (capacity * factor) / 100; 301 302 size_t threshold_bytes_allocated = heap->capacity() * ShenandoahAllocationThreshold / 100; 303 if (available < targetStartMarking && 304 heap->bytes_allocated_since_cm() > threshold_bytes_allocated) 305 { 306 // Need to check that an appropriate number of regions have 307 // been allocated since last concurrent mark too. 308 shouldStartConcurrentMark = true; 309 } 310 311 return shouldStartConcurrentMark; 312 } 313 314 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 315 size_t threshold = ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100; 316 return r->garbage() > threshold; 317 } 318 319 }; 320 321 322 class AdaptiveHeuristics : public ShenandoahHeuristics { 323 private: 324 size_t _max_live_data; 325 double _used_threshold_factor; 326 double _garbage_threshold_factor; 327 double _allocation_threshold_factor; 328 329 uintx _used_threshold; 330 uintx _garbage_threshold; 331 uintx _allocation_threshold; 332 333 size_t _garbage; 334 public: 335 AdaptiveHeuristics() : ShenandoahHeuristics() { 336 _max_live_data = 0; 337 338 _used_threshold = 0; 339 _garbage_threshold = 0; 340 _allocation_threshold = 0; 341 342 _used_threshold_factor = 0.; 343 _garbage_threshold_factor = 0.1; 344 _allocation_threshold_factor = 0.; 345 } 346 347 virtual ~AdaptiveHeuristics() {} 348 349 virtual void start_choose_collection_set() { 350 _garbage = 0; 351 } 352 353 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 354 size_t bytes_alloc = ShenandoahHeap::heap()->bytes_allocated_since_cm(); 355 size_t min_garbage = bytes_alloc/* * 1.1*/; 356 size_t threshold = ShenandoahHeapRegion::RegionSizeBytes * ShenandoahGarbageThreshold / 100; 357 if (_garbage < min_garbage && r->garbage() > threshold) { 358 _garbage += r->garbage(); 359 return true; 360 } else { 361 return false; 362 } 363 } 364 365 virtual bool should_start_concurrent_mark(size_t used, size_t capacity) const { 366 367 ShenandoahHeap* _heap = ShenandoahHeap::heap(); 368 bool shouldStartConcurrentMark = false; 369 OrderAccess::release(); 370 371 size_t max_live_data = _max_live_data; 372 if (max_live_data == 0) { 373 max_live_data = capacity * 0.2; // Very generous initial value. 374 } else { 375 max_live_data *= 1.3; // Add some wiggle room. 376 } 377 size_t max_cycle_allocated = _heap->max_allocated_gc(); 378 if (max_cycle_allocated == 0) { 379 max_cycle_allocated = capacity * 0.3; // Very generous. 380 } else { 381 max_cycle_allocated *= 1.3; // Add 20% wiggle room. Should be enough. 382 } 383 size_t threshold = _heap->capacity() - max_cycle_allocated - max_live_data; 384 if (used > threshold) 385 { 386 shouldStartConcurrentMark = true; 387 } 388 389 return shouldStartConcurrentMark; 390 } 391 392 }; 393 394 class GlobalHeuristics : public DynamicHeuristics { 395 private: 396 size_t _garbage; 397 size_t _min_garbage; 398 public: 399 GlobalHeuristics() : DynamicHeuristics() { 400 if (FLAG_IS_DEFAULT(ShenandoahGarbageThreshold)) { 401 FLAG_SET_DEFAULT(ShenandoahGarbageThreshold, 90); 402 } 403 } 404 virtual ~GlobalHeuristics() {} 405 406 virtual void start_choose_collection_set() { 407 _garbage = 0; 408 size_t heap_garbage = ShenandoahHeap::heap()->garbage(); 409 _min_garbage = heap_garbage * ShenandoahGarbageThreshold / 100; 410 } 411 412 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 413 if (_garbage + immediate_garbage < _min_garbage) { 414 _garbage += r->garbage(); 415 return true; 416 } else { 417 return false; 418 } 419 } 420 421 }; 422 423 class RatioHeuristics : public DynamicHeuristics { 424 private: 425 size_t _garbage; 426 size_t _live; 427 public: 428 RatioHeuristics() : DynamicHeuristics() { 429 if (FLAG_IS_DEFAULT(ShenandoahGarbageThreshold)) { 430 FLAG_SET_DEFAULT(ShenandoahGarbageThreshold, 95); 431 } 432 } 433 virtual ~RatioHeuristics() {} 434 435 virtual void start_choose_collection_set() { 436 _garbage = 0; 437 _live = 0; 438 } 439 440 virtual bool region_in_collection_set(ShenandoahHeapRegion* r, size_t immediate_garbage) { 441 size_t min_ratio = 100 - ShenandoahGarbageThreshold; 442 if (_live * 100 / MAX2(_garbage + immediate_garbage, 1UL) < min_ratio) { 443 _garbage += r->garbage(); 444 _live += r->get_live_data(); 445 return true; 446 } else { 447 return false; 448 } 449 } 450 }; 451 452 ShenandoahCollectorPolicy::ShenandoahCollectorPolicy() : _cycle_counter(0) { 453 454 ShenandoahHeapRegion::setup_heap_region_size(initial_heap_byte_size(), max_heap_byte_size()); 455 456 initialize_all(); 457 458 _tracer = new (ResourceObj::C_HEAP, mtGC) ShenandoahTracer(); 459 _stw_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer(); 460 _conc_timer = new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer(); 461 _user_requested_gcs = 0; 462 _allocation_failure_gcs = 0; 463 _conc_gc_aborted = false; 464 465 _phase_names[init_mark] = "Initial Mark Pauses (net)"; 466 _phase_names[init_mark_gross] = "Initial Mark Pauses (gross)"; 467 _phase_names[final_mark] = "Final Mark Pauses (net)"; 468 _phase_names[final_mark_gross] = "Final Mark Pauses (gross)"; 522 523 _phase_names[full_gc] = "Full GC Times"; 524 _phase_names[full_gc_mark] = " Mark"; 525 _phase_names[full_gc_mark_drain_queues] = " Drain Queues"; 526 _phase_names[full_gc_mark_weakrefs] = " Weak References"; 527 _phase_names[full_gc_mark_class_unloading] = " Class Unloading"; 528 _phase_names[full_gc_calculate_addresses] = " Calculate Addresses"; 529 _phase_names[full_gc_adjust_pointers] = " Adjust Pointers"; 530 _phase_names[full_gc_copy_objects] = " Copy Objects"; 531 532 _phase_names[conc_mark] = "Concurrent Marking Times"; 533 _phase_names[conc_evac] = "Concurrent Evacuation Times"; 534 535 if (ShenandoahGCHeuristics != NULL) { 536 if (strcmp(ShenandoahGCHeuristics, "aggressive") == 0) { 537 log_info(gc, init)("Shenandoah heuristics: aggressive"); 538 _heuristics = new AggressiveHeuristics(); 539 } else if (strcmp(ShenandoahGCHeuristics, "dynamic") == 0) { 540 log_info(gc, init)("Shenandoah heuristics: dynamic"); 541 _heuristics = new DynamicHeuristics(); 542 } else if (strcmp(ShenandoahGCHeuristics, "global") == 0) { 543 log_info(gc, init)("Shenandoah heuristics: global"); 544 _heuristics = new GlobalHeuristics(); 545 } else if (strcmp(ShenandoahGCHeuristics, "ratio") == 0) { 546 log_info(gc, init)("Shenandoah heuristics: ratio"); 547 _heuristics = new RatioHeuristics(); 548 } else if (strcmp(ShenandoahGCHeuristics, "adaptive") == 0) { 549 log_info(gc, init)("Shenandoah heuristics: adaptive"); 550 _heuristics = new AdaptiveHeuristics(); 551 } else if (strcmp(ShenandoahGCHeuristics, "passive") == 0) { 552 log_info(gc, init)("Shenandoah heuristics: passive"); 553 _heuristics = new PassiveHeuristics(); 554 } else { 555 vm_exit_during_initialization("Unknown -XX:ShenandoahGCHeuristics option"); 556 } 557 } else { 558 ShouldNotReachHere(); 559 } 560 _phase_times = new ShenandoahPhaseTimes(MAX2(ConcGCThreads, ParallelGCThreads)); 561 } 562 563 ShenandoahCollectorPolicy* ShenandoahCollectorPolicy::as_pgc_policy() { 564 return this; 565 } 566 567 BarrierSet::Name ShenandoahCollectorPolicy::barrier_set_name() { |