1 /* 2 * Copyright Amazon.com Inc. 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 25 #include "precompiled.hpp" 26 27 #include "gc/shenandoah/shenandoahGeneration.hpp" 28 #include "gc/shenandoah/shenandoahGenerationSizer.hpp" 29 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 30 #include "gc/shenandoah/shenandoahHeapRegion.hpp" 31 #include "gc/shenandoah/shenandoahOldGeneration.hpp" 32 #include "gc/shenandoah/shenandoahYoungGeneration.hpp" 33 #include "gc/shared/gc_globals.hpp" 34 #include "logging/log.hpp" 35 #include "runtime/globals_extension.hpp" 36 37 38 ShenandoahGenerationSizer::ShenandoahGenerationSizer() 39 : _sizer_kind(SizerDefaults), 40 _min_desired_young_regions(0), 41 _max_desired_young_regions(0) { 42 43 if (FLAG_IS_CMDLINE(NewRatio)) { 44 if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { 45 log_warning(gc, ergo)("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); 46 } else { 47 _sizer_kind = SizerNewRatio; 48 return; 49 } 50 } 51 52 if (NewSize > MaxNewSize) { 53 if (FLAG_IS_CMDLINE(MaxNewSize)) { 54 log_warning(gc, ergo)("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " 55 "A new max generation size of " SIZE_FORMAT "k will be used.", 56 NewSize/K, MaxNewSize/K, NewSize/K); 57 } 58 FLAG_SET_ERGO(MaxNewSize, NewSize); 59 } 60 61 if (FLAG_IS_CMDLINE(NewSize)) { 62 _min_desired_young_regions = MAX2(uint(NewSize / ShenandoahHeapRegion::region_size_bytes()), 1U); 63 if (FLAG_IS_CMDLINE(MaxNewSize)) { 64 _max_desired_young_regions = MAX2(uint(MaxNewSize / ShenandoahHeapRegion::region_size_bytes()), 1U); 65 _sizer_kind = SizerMaxAndNewSize; 66 } else { 67 _sizer_kind = SizerNewSizeOnly; 68 } 69 } else if (FLAG_IS_CMDLINE(MaxNewSize)) { 70 _max_desired_young_regions = MAX2(uint(MaxNewSize / ShenandoahHeapRegion::region_size_bytes()), 1U); 71 _sizer_kind = SizerMaxNewSizeOnly; 72 } 73 } 74 75 size_t ShenandoahGenerationSizer::calculate_min_young_regions(size_t heap_region_count) { 76 size_t min_young_regions = (heap_region_count * ShenandoahMinYoungPercentage) / 100; 77 return MAX2(min_young_regions, (size_t) 1U); 78 } 79 80 size_t ShenandoahGenerationSizer::calculate_max_young_regions(size_t heap_region_count) { 81 size_t max_young_regions = (heap_region_count * ShenandoahMaxYoungPercentage) / 100; 82 return MAX2(max_young_regions, (size_t) 1U); 83 } 84 85 void ShenandoahGenerationSizer::recalculate_min_max_young_length(size_t heap_region_count) { 86 assert(heap_region_count > 0, "Heap must be initialized"); 87 88 switch (_sizer_kind) { 89 case SizerDefaults: 90 _min_desired_young_regions = calculate_min_young_regions(heap_region_count); 91 _max_desired_young_regions = calculate_max_young_regions(heap_region_count); 92 break; 93 case SizerNewSizeOnly: 94 _max_desired_young_regions = calculate_max_young_regions(heap_region_count); 95 _max_desired_young_regions = MAX2(_min_desired_young_regions, _max_desired_young_regions); 96 break; 97 case SizerMaxNewSizeOnly: 98 _min_desired_young_regions = calculate_min_young_regions(heap_region_count); 99 _min_desired_young_regions = MIN2(_min_desired_young_regions, _max_desired_young_regions); 100 break; 101 case SizerMaxAndNewSize: 102 // Do nothing. Values set on the command line, don't update them at runtime. 103 break; 104 case SizerNewRatio: 105 _min_desired_young_regions = MAX2(uint(heap_region_count / (NewRatio + 1)), 1U); 106 _max_desired_young_regions = _min_desired_young_regions; 107 break; 108 default: 109 ShouldNotReachHere(); 110 } 111 112 assert(_min_desired_young_regions <= _max_desired_young_regions, "Invalid min/max young gen size values"); 113 } 114 115 void ShenandoahGenerationSizer::heap_size_changed(size_t heap_size) { 116 recalculate_min_max_young_length(heap_size / ShenandoahHeapRegion::region_size_bytes()); 117 } 118 119 bool ShenandoahGenerationSizer::transfer_regions(ShenandoahGeneration* src, ShenandoahGeneration* dst, size_t regions) const { 120 const size_t bytes_to_transfer = regions * ShenandoahHeapRegion::region_size_bytes(); 121 122 if (src->free_unaffiliated_regions() < regions) { 123 // Source does not have enough free regions for this transfer. The caller should have 124 // already capped the transfer based on available unaffiliated regions. 125 return false; 126 } 127 128 if (dst->max_capacity() + bytes_to_transfer > max_size_for(dst)) { 129 // This transfer would cause the destination generation to grow above its configured maximum size. 130 return false; 131 } 132 133 if (src->max_capacity() - bytes_to_transfer < min_size_for(src)) { 134 // This transfer would cause the source generation to shrink below its configured minimum size. 135 return false; 136 } 137 138 src->decrease_capacity(bytes_to_transfer); 139 dst->increase_capacity(bytes_to_transfer); 140 const size_t new_size = dst->max_capacity(); 141 log_info(gc, ergo)("Transfer " SIZE_FORMAT " region(s) from %s to %s, yielding increased size: " PROPERFMT, 142 regions, src->name(), dst->name(), PROPERFMTARGS(new_size)); 143 return true; 144 } 145 146 147 size_t ShenandoahGenerationSizer::max_size_for(ShenandoahGeneration* generation) const { 148 switch (generation->type()) { 149 case YOUNG: 150 return max_young_size(); 151 case OLD: 152 // On the command line, max size of OLD is specified indirectly, by setting a minimum size of young. 153 // OLD is what remains within the heap after YOUNG has been sized. 154 return ShenandoahHeap::heap()->max_capacity() - min_young_size(); 155 default: 156 ShouldNotReachHere(); 157 return 0; 158 } 159 } 160 161 size_t ShenandoahGenerationSizer::min_size_for(ShenandoahGeneration* generation) const { 162 switch (generation->type()) { 163 case YOUNG: 164 return min_young_size(); 165 case OLD: 166 // On the command line, min size of OLD is specified indirectly, by setting a maximum size of young. 167 // OLD is what remains within the heap after YOUNG has been sized. 168 return ShenandoahHeap::heap()->max_capacity() - max_young_size(); 169 default: 170 ShouldNotReachHere(); 171 return 0; 172 } 173 } 174 175 176 // Returns true iff transfer is successful 177 bool ShenandoahGenerationSizer::transfer_to_old(size_t regions) const { 178 ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); 179 return transfer_regions(heap->young_generation(), heap->old_generation(), regions); 180 } 181 182 // This is used when promoting humongous or highly utilized regular regions in place. It is not required in this situation 183 // that the transferred regions be unaffiliated. 184 void ShenandoahGenerationSizer::force_transfer_to_old(size_t regions) const { 185 ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); 186 ShenandoahGeneration* old_gen = heap->old_generation(); 187 ShenandoahGeneration* young_gen = heap->young_generation(); 188 const size_t bytes_to_transfer = regions * ShenandoahHeapRegion::region_size_bytes(); 189 190 young_gen->decrease_capacity(bytes_to_transfer); 191 old_gen->increase_capacity(bytes_to_transfer); 192 const size_t new_size = old_gen->max_capacity(); 193 log_info(gc, ergo)("Forcing transfer of " SIZE_FORMAT " region(s) from %s to %s, yielding increased size: " PROPERFMT, 194 regions, young_gen->name(), old_gen->name(), PROPERFMTARGS(new_size)); 195 } 196 197 198 bool ShenandoahGenerationSizer::transfer_to_young(size_t regions) const { 199 ShenandoahGenerationalHeap* heap = ShenandoahGenerationalHeap::heap(); 200 return transfer_regions(heap->old_generation(), heap->young_generation(), regions); 201 } 202 203 size_t ShenandoahGenerationSizer::min_young_size() const { 204 return min_young_regions() * ShenandoahHeapRegion::region_size_bytes(); 205 } 206 207 size_t ShenandoahGenerationSizer::max_young_size() const { 208 return max_young_regions() * ShenandoahHeapRegion::region_size_bytes(); 209 }