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 #include "gc/g1/g1CollectedHeap.inline.hpp"
27 #include "gc/g1/g1ErgoVerbose.hpp"
28 #include "gc/g1/g1IHOPControl.hpp"
29
30 G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) :
31 _initial_ihop_percent(initial_ihop_percent),
32 _target_occupancy(target_occupancy) {
33 assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "Initial IHOP value must be between 0 and 100 but is %.3f", initial_ihop_percent);
34 }
35
36 G1StaticIHOPControl::G1StaticIHOPControl(double ihop_percent, size_t target_occupancy) :
37 G1IHOPControl(ihop_percent, target_occupancy),
38 _last_allocation_time_s(0.0),
39 _last_allocated_bytes(0),
40 _last_marking_length_s(0.0) {
41 assert(_target_occupancy > 0, "Target occupancy must be larger than zero.");
42 }
43
44 void G1StaticIHOPControl::print() {
45 ergo_verbose6(ErgoIHOP,
46 "basic information",
47 ergo_format_reason("value update")
48 ergo_format_byte_perc("threshold")
49 ergo_format_byte("target occupancy")
50 ergo_format_byte("current occupancy")
51 ergo_format_double("recent old gen allocation rate")
52 ergo_format_ms("recent marking phase length"),
53 get_conc_mark_start_threshold(),
54 _initial_ihop_percent,
55 _target_occupancy,
56 G1CollectedHeap::heap()->used(),
57 _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0,
58 _last_marking_length_s * 1000.0);
59 }
60
61 #ifndef PRODUCT
62 static void test_update(G1IHOPControl* ctrl, double alloc_time, size_t alloc_amount, size_t young_size, double mark_time) {
63 for (int i = 0; i < 100; i++) {
64 ctrl->update_allocation_info(alloc_time, alloc_amount, young_size);
65 ctrl->update_marking_length(mark_time);
66 }
67 }
68
69 void G1StaticIHOPControl::test() {
70 size_t const initial_ihop = 45;
71
72 G1StaticIHOPControl ctrl(initial_ihop, 100);
73 size_t threshold;
74
75 threshold = ctrl.get_conc_mark_start_threshold();
76 assert(threshold == initial_ihop,
77 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
78
82 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
83
84 ctrl.update_marking_length(1000.0);
85 threshold = ctrl.get_conc_mark_start_threshold();
86 assert(threshold == initial_ihop,
87 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
88
89 // Whatever we pass, the IHOP value must stay the same.
90 test_update(&ctrl, 2, 10, 10, 3);
91 threshold = ctrl.get_conc_mark_start_threshold();
92 assert(threshold == initial_ihop,
93 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
94
95 test_update(&ctrl, 12, 10, 10, 3);
96 threshold = ctrl.get_conc_mark_start_threshold();
97 assert(threshold == initial_ihop,
98 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
99 }
100 #endif
101
102 #ifndef PRODUCT
103 void IHOP_test() {
104 G1StaticIHOPControl::test();
105 }
106 #endif
|
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 #include "gc/g1/g1CollectedHeap.inline.hpp"
27 #include "gc/g1/g1ErgoVerbose.hpp"
28 #include "gc/g1/g1IHOPControl.hpp"
29 #include "gc/g1/g1Predictions.hpp"
30
31 G1IHOPControl::G1IHOPControl(double initial_ihop_percent, size_t target_occupancy) :
32 _initial_ihop_percent(initial_ihop_percent),
33 _target_occupancy(target_occupancy) {
34 assert(_initial_ihop_percent >= 0.0 && _initial_ihop_percent <= 100.0, "Initial IHOP value must be between 0 and 100 but is %.3f", initial_ihop_percent);
35 }
36
37 G1StaticIHOPControl::G1StaticIHOPControl(double ihop_percent, size_t target_occupancy) :
38 G1IHOPControl(ihop_percent, target_occupancy),
39 _last_allocation_time_s(0.0),
40 _last_allocated_bytes(0),
41 _last_marking_length_s(0.0) {
42 assert(_target_occupancy > 0, "Target occupancy must be larger than zero.");
43 }
44
45 void G1StaticIHOPControl::print() {
46 ergo_verbose6(ErgoIHOP,
47 "basic information",
48 ergo_format_reason("value update")
49 ergo_format_byte_perc("threshold")
50 ergo_format_byte("target occupancy")
51 ergo_format_byte("current occupancy")
52 ergo_format_double("recent old gen allocation rate")
53 ergo_format_double("recent marking phase length"),
54 get_conc_mark_start_threshold(),
55 _initial_ihop_percent,
56 _target_occupancy,
57 G1CollectedHeap::heap()->used(),
58 _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0,
59 _last_marking_length_s);
60 }
61
62 #ifndef PRODUCT
63 static void test_update(G1IHOPControl* ctrl, double alloc_time, size_t alloc_amount, size_t young_size, double mark_time) {
64 for (int i = 0; i < 100; i++) {
65 ctrl->update_allocation_info(alloc_time, alloc_amount, young_size);
66 ctrl->update_marking_length(mark_time);
67 }
68 }
69
70 void G1StaticIHOPControl::test() {
71 size_t const initial_ihop = 45;
72
73 G1StaticIHOPControl ctrl(initial_ihop, 100);
74 size_t threshold;
75
76 threshold = ctrl.get_conc_mark_start_threshold();
77 assert(threshold == initial_ihop,
78 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
79
83 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
84
85 ctrl.update_marking_length(1000.0);
86 threshold = ctrl.get_conc_mark_start_threshold();
87 assert(threshold == initial_ihop,
88 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
89
90 // Whatever we pass, the IHOP value must stay the same.
91 test_update(&ctrl, 2, 10, 10, 3);
92 threshold = ctrl.get_conc_mark_start_threshold();
93 assert(threshold == initial_ihop,
94 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
95
96 test_update(&ctrl, 12, 10, 10, 3);
97 threshold = ctrl.get_conc_mark_start_threshold();
98 assert(threshold == initial_ihop,
99 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_ihop, threshold);
100 }
101 #endif
102
103 G1AdaptiveIHOPControl::G1AdaptiveIHOPControl(double ihop_percent,
104 size_t initial_target_occupancy,
105 G1Predictions const* predictor,
106 size_t heap_reserve_percent,
107 size_t heap_waste_percent) :
108 G1IHOPControl(ihop_percent, initial_target_occupancy),
109 _predictor(predictor),
110 _marking_times_s(10, 0.95),
111 _allocation_rate_s(10, 0.95),
112 _last_unrestrained_young_size(0),
113 _current_threshold(0.0),
114 _heap_reserve_percent(heap_reserve_percent),
115 _heap_waste_percent(heap_waste_percent)
116 {
117 calculate();
118 }
119
120 void G1AdaptiveIHOPControl::calculate() {
121 if (have_enough_data_for_prediction()) {
122 double pred_marking_time = _predictor->get_new_prediction(&_marking_times_s);
123 double pred_promotion_rate = _predictor->get_new_prediction(&_allocation_rate_s);
124
125 size_t predicted_needed_bytes_during_marking =
126 (pred_marking_time * pred_promotion_rate +
127 _last_unrestrained_young_size); // In reality we would need the maximum size of the young gen during marking. This is a conservative estimate.
128
129 size_t internal_threshold = actual_target_threshold();
130 size_t predicted_initiating_threshold = predicted_needed_bytes_during_marking < internal_threshold ?
131 internal_threshold - predicted_needed_bytes_during_marking :
132 0;
133 _current_threshold = predicted_initiating_threshold;
134 } else {
135 // Use the initial value.
136 _current_threshold = _initial_ihop_percent * _target_occupancy / 100.0;
137 }
138 }
139
140 size_t G1AdaptiveIHOPControl::actual_target_threshold() const {
141 // The actual target threshold takes the heap reserve and the expected waste in
142 // free space into account.
143 // _heap_reserve is that part of the total heap capacity that is reserved for
144 // eventual promotion failure.
145 // _heap_waste is the amount of space will never be reclaimed in any
146 // heap, so can not be used for allocation during marking and must always be
147 // considered.
148
149 double safe_total_heap_percentage = MIN2((double)(_heap_reserve_percent + _heap_waste_percent), 100.0);
150
151 return MIN2(
152 G1CollectedHeap::heap()->max_capacity() * (100.0 - safe_total_heap_percentage) / 100.0,
153 _target_occupancy * (100.0 - _heap_waste_percent) / 100.0
154 );
155 }
156
157 bool G1AdaptiveIHOPControl::have_enough_data_for_prediction() const {
158 return ((size_t)_marking_times_s.num() >= G1AdaptiveIHOPNumInitialSamples) &&
159 ((size_t)_allocation_rate_s.num() >= G1AdaptiveIHOPNumInitialSamples);
160 }
161
162 void G1AdaptiveIHOPControl::set_target_occupancy(size_t target_occupancy) {
163 _target_occupancy = target_occupancy;
164 }
165
166 size_t G1AdaptiveIHOPControl::get_conc_mark_start_threshold() {
167 calculate();
168 return _current_threshold;
169 }
170
171 void G1AdaptiveIHOPControl::update_allocation_info(double allocation_time_s, size_t allocated_bytes, size_t additional_buffer_size) {
172 assert(allocation_time_s >= 0.0, "Allocation time must be positive but is %.3f", allocation_time_s);
173 double allocation_rate = (double) allocated_bytes / allocation_time_s;
174 _allocation_rate_s.add(allocation_rate);
175
176 _last_allocation_bytes = allocated_bytes;
177 _last_unrestrained_young_size = additional_buffer_size;
178 }
179
180 void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) {
181 assert(marking_length_s >= 0.0, "Marking length must be larger than zero but is %.3f", marking_length_s);
182 _marking_times_s.add(marking_length_s);
183 }
184
185 static double percentage_of(double quantity, double base_quantity) {
186 return base_quantity > 0.0 ? (quantity / base_quantity) * 100.0 : 0.0;
187 }
188
189 void G1AdaptiveIHOPControl::print() {
190 ergo_verbose6(ErgoIHOP,
191 "basic information",
192 ergo_format_reason("value update")
193 ergo_format_byte_perc("threshold")
194 ergo_format_byte("target occupancy")
195 ergo_format_byte("current occupancy")
196 ergo_format_double("recent old gen allocation rate")
197 ergo_format_double("recent marking phase length"),
198 get_conc_mark_start_threshold(),
199 percentage_of(get_conc_mark_start_threshold(), _target_occupancy),
200 _target_occupancy,
201 G1CollectedHeap::heap()->used(),
202 _allocation_rate_s.last(),
203 _marking_times_s.last()
204 );
205 size_t actual_target = actual_target_threshold();
206 ergo_verbose6(ErgoIHOP,
207 "adaptive IHOP information",
208 ergo_format_reason("value update")
209 ergo_format_byte_perc("threshold")
210 ergo_format_byte("internal target occupancy")
211 ergo_format_double("predicted old gen allocation rate")
212 ergo_format_double("predicted marking phase length")
213 ergo_format_str("prediction active"),
214 get_conc_mark_start_threshold(),
215 percentage_of(get_conc_mark_start_threshold(), actual_target),
216 actual_target,
217 _predictor->get_new_prediction(&_allocation_rate_s),
218 _predictor->get_new_prediction(&_marking_times_s),
219 have_enough_data_for_prediction() ? "true" : "false"
220 );
221 }
222
223 #ifndef PRODUCT
224 void G1AdaptiveIHOPControl::test() {
225 size_t const initial_threshold = 45;
226 size_t const young_size = 10;
227 size_t const target_size = 100;
228
229 // The final IHOP value is always
230 // target_size - (young_size + alloc_amount/alloc_time * marking_time)
231
232 G1Predictions pred(0.95);
233 G1AdaptiveIHOPControl ctrl(initial_threshold, target_size, &pred, 0, 0);
234
235 // First "load".
236 size_t const alloc_time1 = 2;
237 size_t const alloc_amount1 = 10;
238 size_t const marking_time1 = 2;
239 size_t const settled_ihop1 = target_size - (young_size + alloc_amount1/alloc_time1 * marking_time1);
240
241 size_t threshold;
242 threshold = ctrl.get_conc_mark_start_threshold();
243 assert(threshold == initial_threshold,
244 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_threshold, threshold);
245 for (size_t i = 0; i < G1AdaptiveIHOPNumInitialSamples - 1; i++) {
246 ctrl.update_allocation_info(alloc_time1, alloc_amount1, young_size);
247 ctrl.update_marking_length(marking_time1);
248 // Not enough data yet.
249 threshold = ctrl.get_conc_mark_start_threshold();
250 assert(threshold == initial_threshold,
251 "Expected IHOP threshold of " SIZE_FORMAT " but is " SIZE_FORMAT, initial_threshold, threshold);
252 }
253
254 test_update(&ctrl, alloc_time1, alloc_amount1, young_size, marking_time1);
255
256 threshold = ctrl.get_conc_mark_start_threshold();
257 assert(threshold == settled_ihop1,
258 "Expected IHOP threshold to settle at " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop1, threshold);
259
260 // Second "load". A bit higher allocation rate.
261 size_t const alloc_time2 = 2;
262 size_t const alloc_amount2 = 30;
263 size_t const marking_time2 = 2;
264 size_t const settled_ihop2 = target_size - (young_size + alloc_amount2/alloc_time2 * marking_time2);
265
266 test_update(&ctrl, alloc_time2, alloc_amount2, young_size, marking_time2);
267
268 threshold = ctrl.get_conc_mark_start_threshold();
269 assert(threshold < settled_ihop1,
270 "Expected IHOP threshold to settle at a value lower than " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop1, threshold);
271
272 // Third "load". Very high (impossible) allocation rate.
273 size_t const alloc_time3 = 1;
274 size_t const alloc_amount3 = 50;
275 size_t const marking_time3 = 2;
276 size_t const settled_ihop3 = 0;
277
278 test_update(&ctrl, alloc_time3, alloc_amount3, young_size, marking_time3);
279 threshold = ctrl.get_conc_mark_start_threshold();
280
281 assert(threshold == settled_ihop3,
282 "Expected IHOP threshold to settle at " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop3, threshold);
283
284 // And back to some arbitrary value.
285 test_update(&ctrl, alloc_time2, alloc_amount2, young_size, marking_time2);
286
287 threshold = ctrl.get_conc_mark_start_threshold();
288 assert(threshold > settled_ihop3,
289 "Expected IHOP threshold to settle at value larger than " SIZE_FORMAT " but is " SIZE_FORMAT, settled_ihop3, threshold);
290 }
291
292 void IHOP_test() {
293 G1StaticIHOPControl::test();
294 G1AdaptiveIHOPControl::test();
295 }
296 #endif
|