1 /* 2 * Copyright (c) 2021, Amazon.com, Inc. and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 #include "precompiled.hpp" 25 26 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" 27 #include "gc/shenandoah/mode/shenandoahMode.hpp" 28 #include "gc/shenandoah/shenandoahControlThread.hpp" 29 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 30 #include "gc/shenandoah/shenandoahOldGeneration.hpp" 31 #include "gc/shenandoah/shenandoahRegulatorThread.hpp" 32 #include "gc/shenandoah/shenandoahYoungGeneration.hpp" 33 #include "logging/log.hpp" 34 35 static ShenandoahHeuristics* get_heuristics(ShenandoahGeneration* nullable) { 36 return nullable != nullptr ? nullable->heuristics() : nullptr; 37 } 38 39 ShenandoahRegulatorThread::ShenandoahRegulatorThread(ShenandoahControlThread* control_thread) : 40 ConcurrentGCThread(), 41 _control_thread(control_thread), 42 _sleep(ShenandoahControlIntervalMin), 43 _last_sleep_adjust_time(os::elapsedTime()) { 44 45 ShenandoahHeap* heap = ShenandoahHeap::heap(); 46 _old_heuristics = get_heuristics(heap->old_generation()); 47 _young_heuristics = get_heuristics(heap->young_generation()); 48 _global_heuristics = get_heuristics(heap->global_generation()); 49 50 create_and_start(); 51 } 52 53 void ShenandoahRegulatorThread::run_service() { 54 if (ShenandoahHeap::heap()->mode()->is_generational()) { 55 if (ShenandoahAllowOldMarkingPreemption) { 56 regulate_concurrent_cycles(); 57 } else { 58 regulate_interleaved_cycles(); 59 } 60 } else { 61 regulate_heap(); 62 } 63 64 log_info(gc)("%s: Done.", name()); 65 } 66 67 void ShenandoahRegulatorThread::regulate_concurrent_cycles() { 68 assert(_young_heuristics != nullptr, "Need young heuristics."); 69 assert(_old_heuristics != nullptr, "Need old heuristics."); 70 71 while (!should_terminate()) { 72 ShenandoahControlThread::GCMode mode = _control_thread->gc_mode(); 73 if (mode == ShenandoahControlThread::none) { 74 if (should_unload_classes()) { 75 if (_control_thread->request_concurrent_gc(GLOBAL)) { 76 log_info(gc)("Heuristics request for global (unload classes) accepted."); 77 } 78 } else { 79 if (start_old_cycle()) { 80 log_info(gc)("Heuristics request for old collection accepted"); 81 } else if (start_young_cycle()) { 82 log_info(gc)("Heuristics request for young collection accepted"); 83 } 84 } 85 } else if (mode == ShenandoahControlThread::servicing_old) { 86 if (start_young_cycle()) { 87 log_info(gc)("Heuristics request to interrupt old for young collection accepted"); 88 } 89 } 90 91 regulator_sleep(); 92 } 93 } 94 95 void ShenandoahRegulatorThread::regulate_interleaved_cycles() { 96 assert(_young_heuristics != nullptr, "Need young heuristics."); 97 assert(_global_heuristics != nullptr, "Need global heuristics."); 98 99 while (!should_terminate()) { 100 if (_control_thread->gc_mode() == ShenandoahControlThread::none) { 101 if (start_global_cycle()) { 102 log_info(gc)("Heuristics request for global collection accepted."); 103 } else if (start_young_cycle()) { 104 log_info(gc)("Heuristics request for young collection accepted."); 105 } 106 } 107 108 regulator_sleep(); 109 } 110 } 111 112 void ShenandoahRegulatorThread::regulate_heap() { 113 assert(_global_heuristics != nullptr, "Need global heuristics."); 114 115 while (!should_terminate()) { 116 if (_control_thread->gc_mode() == ShenandoahControlThread::none) { 117 if (start_global_cycle()) { 118 log_info(gc)("Heuristics request for global collection accepted."); 119 } 120 } 121 122 regulator_sleep(); 123 } 124 } 125 126 void ShenandoahRegulatorThread::regulator_sleep() { 127 // Wait before performing the next action. If allocation happened during this wait, 128 // we exit sooner, to let heuristics re-evaluate new conditions. If we are at idle, 129 // back off exponentially. 130 double current = os::elapsedTime(); 131 132 if (_heap_changed.try_unset()) { 133 _sleep = ShenandoahControlIntervalMin; 134 } else if ((current - _last_sleep_adjust_time) * 1000 > ShenandoahControlIntervalAdjustPeriod){ 135 _sleep = MIN2<int>(ShenandoahControlIntervalMax, MAX2(1, _sleep * 2)); 136 _last_sleep_adjust_time = current; 137 } 138 139 os::naked_short_sleep(_sleep); 140 } 141 142 bool ShenandoahRegulatorThread::start_old_cycle() { 143 return _old_heuristics->should_start_gc() && _control_thread->request_concurrent_gc(OLD); 144 } 145 146 bool ShenandoahRegulatorThread::start_young_cycle() { 147 return _young_heuristics->should_start_gc() && _control_thread->request_concurrent_gc(YOUNG); 148 } 149 150 bool ShenandoahRegulatorThread::start_global_cycle() { 151 return _global_heuristics->should_start_gc() && _control_thread->request_concurrent_gc(GLOBAL); 152 } 153 154 void ShenandoahRegulatorThread::stop_service() { 155 log_info(gc)("%s: Stop requested.", name()); 156 } 157 158 bool ShenandoahRegulatorThread::should_unload_classes() { 159 // The heuristics delegate this decision to the collector policy, which is based on the number 160 // of cycles started. 161 return _global_heuristics->should_unload_classes(); 162 } 163