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 }