1 | /* |
2 | * Copyright (c) 2004, 2019, Oracle 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 | |
25 | #include "precompiled.hpp" |
26 | #include "gc/shared/adaptiveSizePolicy.hpp" |
27 | #include "gc/shared/gcCause.hpp" |
28 | #include "gc/shared/gcUtil.inline.hpp" |
29 | #include "logging/log.hpp" |
30 | #include "runtime/timer.hpp" |
31 | |
32 | elapsedTimer AdaptiveSizePolicy::_minor_timer; |
33 | elapsedTimer AdaptiveSizePolicy::_major_timer; |
34 | |
35 | // The throughput goal is implemented as |
36 | // _throughput_goal = 1 - ( 1 / (1 + gc_cost_ratio)) |
37 | // gc_cost_ratio is the ratio |
38 | // application cost / gc cost |
39 | // For example a gc_cost_ratio of 4 translates into a |
40 | // throughput goal of .80 |
41 | |
42 | AdaptiveSizePolicy::AdaptiveSizePolicy(size_t init_eden_size, |
43 | size_t init_promo_size, |
44 | size_t init_survivor_size, |
45 | double gc_pause_goal_sec, |
46 | uint gc_cost_ratio) : |
47 | _throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))), |
48 | _eden_size(init_eden_size), |
49 | _promo_size(init_promo_size), |
50 | _survivor_size(init_survivor_size), |
51 | _avg_minor_pause(new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding)), |
52 | _avg_minor_interval(new AdaptiveWeightedAverage(AdaptiveTimeWeight)), |
53 | _avg_minor_gc_cost(new AdaptiveWeightedAverage(AdaptiveTimeWeight)), |
54 | _avg_major_interval(new AdaptiveWeightedAverage(AdaptiveTimeWeight)), |
55 | _avg_major_gc_cost(new AdaptiveWeightedAverage(AdaptiveTimeWeight)), |
56 | _avg_young_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)), |
57 | _avg_eden_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)), |
58 | _avg_old_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)), |
59 | _avg_survived(new AdaptivePaddedAverage(AdaptiveSizePolicyWeight, SurvivorPadding)), |
60 | _avg_pretenured(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, SurvivorPadding)), |
61 | _minor_pause_old_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)), |
62 | _minor_pause_young_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)), |
63 | _minor_collection_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)), |
64 | _major_collection_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)), |
65 | _latest_minor_mutator_interval_seconds(0), |
66 | _threshold_tolerance_percent(1.0 + ThresholdTolerance/100.0), |
67 | _gc_pause_goal_sec(gc_pause_goal_sec), |
68 | _young_gen_policy_is_ready(false), |
69 | _change_young_gen_for_min_pauses(0), |
70 | _change_old_gen_for_maj_pauses(0), |
71 | _change_old_gen_for_throughput(0), |
72 | _change_young_gen_for_throughput(0), |
73 | _increment_tenuring_threshold_for_gc_cost(false), |
74 | _decrement_tenuring_threshold_for_gc_cost(false), |
75 | _decrement_tenuring_threshold_for_survivor_limit(false), |
76 | _decrease_for_footprint(0), |
77 | _decide_at_full_gc(0), |
78 | _young_gen_change_for_minor_throughput(0), |
79 | _old_gen_change_for_major_throughput(0) { |
80 | |
81 | // Start the timers |
82 | _minor_timer.start(); |
83 | } |
84 | |
85 | bool AdaptiveSizePolicy::tenuring_threshold_change() const { |
86 | return decrement_tenuring_threshold_for_gc_cost() || |
87 | increment_tenuring_threshold_for_gc_cost() || |
88 | decrement_tenuring_threshold_for_survivor_limit(); |
89 | } |
90 | |
91 | void AdaptiveSizePolicy::minor_collection_begin() { |
92 | // Update the interval time |
93 | _minor_timer.stop(); |
94 | // Save most recent collection time |
95 | _latest_minor_mutator_interval_seconds = _minor_timer.seconds(); |
96 | _minor_timer.reset(); |
97 | _minor_timer.start(); |
98 | } |
99 | |
100 | void AdaptiveSizePolicy::update_minor_pause_young_estimator( |
101 | double minor_pause_in_ms) { |
102 | double eden_size_in_mbytes = ((double)_eden_size)/((double)M); |
103 | _minor_pause_young_estimator->update(eden_size_in_mbytes, |
104 | minor_pause_in_ms); |
105 | } |
106 | |
107 | void AdaptiveSizePolicy::minor_collection_end(GCCause::Cause gc_cause) { |
108 | // Update the pause time. |
109 | _minor_timer.stop(); |
110 | |
111 | if (!GCCause::is_user_requested_gc(gc_cause) || |
112 | UseAdaptiveSizePolicyWithSystemGC) { |
113 | double minor_pause_in_seconds = _minor_timer.seconds(); |
114 | double minor_pause_in_ms = minor_pause_in_seconds * MILLIUNITS; |
115 | |
116 | // Sample for performance counter |
117 | _avg_minor_pause->sample(minor_pause_in_seconds); |
118 | |
119 | // Cost of collection (unit-less) |
120 | double collection_cost = 0.0; |
121 | if ((_latest_minor_mutator_interval_seconds > 0.0) && |
122 | (minor_pause_in_seconds > 0.0)) { |
123 | double interval_in_seconds = |
124 | _latest_minor_mutator_interval_seconds + minor_pause_in_seconds; |
125 | collection_cost = |
126 | minor_pause_in_seconds / interval_in_seconds; |
127 | _avg_minor_gc_cost->sample(collection_cost); |
128 | // Sample for performance counter |
129 | _avg_minor_interval->sample(interval_in_seconds); |
130 | } |
131 | |
132 | // The policy does not have enough data until at least some |
133 | // young collections have been done. |
134 | _young_gen_policy_is_ready = |
135 | (_avg_minor_gc_cost->count() >= AdaptiveSizePolicyReadyThreshold); |
136 | |
137 | // Calculate variables used to estimate pause time vs. gen sizes |
138 | double eden_size_in_mbytes = ((double)_eden_size) / ((double)M); |
139 | update_minor_pause_young_estimator(minor_pause_in_ms); |
140 | update_minor_pause_old_estimator(minor_pause_in_ms); |
141 | |
142 | log_trace(gc, ergo)("AdaptiveSizePolicy::minor_collection_end: minor gc cost: %f average: %f" , |
143 | collection_cost, _avg_minor_gc_cost->average()); |
144 | log_trace(gc, ergo)(" minor pause: %f minor period %f" , |
145 | minor_pause_in_ms, _latest_minor_mutator_interval_seconds * MILLIUNITS); |
146 | |
147 | // Calculate variable used to estimate collection cost vs. gen sizes |
148 | assert(collection_cost >= 0.0, "Expected to be non-negative" ); |
149 | _minor_collection_estimator->update(eden_size_in_mbytes, collection_cost); |
150 | } |
151 | |
152 | // Interval times use this timer to measure the mutator time. |
153 | // Reset the timer after the GC pause. |
154 | _minor_timer.reset(); |
155 | _minor_timer.start(); |
156 | } |
157 | |
158 | size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden, uint percent_change) { |
159 | size_t eden_heap_delta; |
160 | eden_heap_delta = cur_eden / 100 * percent_change; |
161 | return eden_heap_delta; |
162 | } |
163 | |
164 | size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden) { |
165 | return eden_increment(cur_eden, YoungGenerationSizeIncrement); |
166 | } |
167 | |
168 | size_t AdaptiveSizePolicy::eden_decrement(size_t cur_eden) { |
169 | size_t eden_heap_delta = eden_increment(cur_eden) / |
170 | AdaptiveSizeDecrementScaleFactor; |
171 | return eden_heap_delta; |
172 | } |
173 | |
174 | size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo, uint percent_change) { |
175 | size_t promo_heap_delta; |
176 | promo_heap_delta = cur_promo / 100 * percent_change; |
177 | return promo_heap_delta; |
178 | } |
179 | |
180 | size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo) { |
181 | return promo_increment(cur_promo, TenuredGenerationSizeIncrement); |
182 | } |
183 | |
184 | size_t AdaptiveSizePolicy::promo_decrement(size_t cur_promo) { |
185 | size_t promo_heap_delta = promo_increment(cur_promo); |
186 | promo_heap_delta = promo_heap_delta / AdaptiveSizeDecrementScaleFactor; |
187 | return promo_heap_delta; |
188 | } |
189 | |
190 | double AdaptiveSizePolicy::time_since_major_gc() const { |
191 | _major_timer.stop(); |
192 | double result = _major_timer.seconds(); |
193 | _major_timer.start(); |
194 | return result; |
195 | } |
196 | |
197 | // Linear decay of major gc cost |
198 | double AdaptiveSizePolicy::decaying_major_gc_cost() const { |
199 | double major_interval = major_gc_interval_average_for_decay(); |
200 | double major_gc_cost_average = major_gc_cost(); |
201 | double decayed_major_gc_cost = major_gc_cost_average; |
202 | if(time_since_major_gc() > 0.0) { |
203 | decayed_major_gc_cost = major_gc_cost() * |
204 | (((double) AdaptiveSizeMajorGCDecayTimeScale) * major_interval) |
205 | / time_since_major_gc(); |
206 | } |
207 | |
208 | // The decayed cost should always be smaller than the |
209 | // average cost but the vagaries of finite arithmetic could |
210 | // produce a larger value in decayed_major_gc_cost so protect |
211 | // against that. |
212 | return MIN2(major_gc_cost_average, decayed_major_gc_cost); |
213 | } |
214 | |
215 | // Use a value of the major gc cost that has been decayed |
216 | // by the factor |
217 | // |
218 | // average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale / |
219 | // time-since-last-major-gc |
220 | // |
221 | // if the average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale |
222 | // is less than time-since-last-major-gc. |
223 | // |
224 | // In cases where there are initial major gc's that |
225 | // are of a relatively high cost but no later major |
226 | // gc's, the total gc cost can remain high because |
227 | // the major gc cost remains unchanged (since there are no major |
228 | // gc's). In such a situation the value of the unchanging |
229 | // major gc cost can keep the mutator throughput below |
230 | // the goal when in fact the major gc cost is becoming diminishingly |
231 | // small. Use the decaying gc cost only to decide whether to |
232 | // adjust for throughput. Using it also to determine the adjustment |
233 | // to be made for throughput also seems reasonable but there is |
234 | // no test case to use to decide if it is the right thing to do |
235 | // don't do it yet. |
236 | |
237 | double AdaptiveSizePolicy::decaying_gc_cost() const { |
238 | double decayed_major_gc_cost = major_gc_cost(); |
239 | double avg_major_interval = major_gc_interval_average_for_decay(); |
240 | if (UseAdaptiveSizeDecayMajorGCCost && |
241 | (AdaptiveSizeMajorGCDecayTimeScale > 0) && |
242 | (avg_major_interval > 0.00)) { |
243 | double time_since_last_major_gc = time_since_major_gc(); |
244 | |
245 | // Decay the major gc cost? |
246 | if (time_since_last_major_gc > |
247 | ((double) AdaptiveSizeMajorGCDecayTimeScale) * avg_major_interval) { |
248 | |
249 | // Decay using the time-since-last-major-gc |
250 | decayed_major_gc_cost = decaying_major_gc_cost(); |
251 | log_trace(gc, ergo)("decaying_gc_cost: major interval average: %f time since last major gc: %f" , |
252 | avg_major_interval, time_since_last_major_gc); |
253 | log_trace(gc, ergo)(" major gc cost: %f decayed major gc cost: %f" , |
254 | major_gc_cost(), decayed_major_gc_cost); |
255 | } |
256 | } |
257 | double result = MIN2(1.0, decayed_major_gc_cost + minor_gc_cost()); |
258 | return result; |
259 | } |
260 | |
261 | |
262 | void AdaptiveSizePolicy::clear_generation_free_space_flags() { |
263 | set_change_young_gen_for_min_pauses(0); |
264 | set_change_old_gen_for_maj_pauses(0); |
265 | |
266 | set_change_old_gen_for_throughput(0); |
267 | set_change_young_gen_for_throughput(0); |
268 | set_decrease_for_footprint(0); |
269 | set_decide_at_full_gc(0); |
270 | } |
271 | |
272 | class AdaptiveSizePolicyTimeOverheadTester: public GCOverheadTester { |
273 | double _gc_cost; |
274 | |
275 | public: |
276 | AdaptiveSizePolicyTimeOverheadTester(double gc_cost) : _gc_cost(gc_cost) {} |
277 | |
278 | bool is_exceeded() { |
279 | return _gc_cost > (GCTimeLimit / 100.0); |
280 | } |
281 | }; |
282 | |
283 | class AdaptiveSizePolicySpaceOverheadTester: public GCOverheadTester { |
284 | size_t _eden_live; |
285 | size_t _max_old_gen_size; |
286 | size_t _max_eden_size; |
287 | size_t _promo_size; |
288 | double _avg_eden_live; |
289 | double _avg_old_live; |
290 | |
291 | public: |
292 | AdaptiveSizePolicySpaceOverheadTester(size_t eden_live, |
293 | size_t max_old_gen_size, |
294 | size_t max_eden_size, |
295 | size_t promo_size, |
296 | double avg_eden_live, |
297 | double avg_old_live) : |
298 | _eden_live(eden_live), |
299 | _max_old_gen_size(max_old_gen_size), |
300 | _max_eden_size(max_eden_size), |
301 | _promo_size(promo_size), |
302 | _avg_eden_live(avg_eden_live), |
303 | _avg_old_live(avg_old_live) {} |
304 | |
305 | bool is_exceeded() { |
306 | // _max_eden_size is the upper limit on the size of eden based on |
307 | // the maximum size of the young generation and the sizes |
308 | // of the survivor space. |
309 | // The question being asked is whether the space being recovered by |
310 | // a collection is low. |
311 | // free_in_eden is the free space in eden after a collection and |
312 | // free_in_old_gen is the free space in the old generation after |
313 | // a collection. |
314 | // |
315 | // Use the minimum of the current value of the live in eden |
316 | // or the average of the live in eden. |
317 | // If the current value drops quickly, that should be taken |
318 | // into account (i.e., don't trigger if the amount of free |
319 | // space has suddenly jumped up). If the current is much |
320 | // higher than the average, use the average since it represents |
321 | // the longer term behavior. |
322 | const size_t live_in_eden = |
323 | MIN2(_eden_live, (size_t)_avg_eden_live); |
324 | const size_t free_in_eden = _max_eden_size > live_in_eden ? |
325 | _max_eden_size - live_in_eden : 0; |
326 | const size_t free_in_old_gen = (size_t)(_max_old_gen_size - _avg_old_live); |
327 | const size_t total_free_limit = free_in_old_gen + free_in_eden; |
328 | const size_t total_mem = _max_old_gen_size + _max_eden_size; |
329 | const double free_limit_ratio = GCHeapFreeLimit / 100.0; |
330 | const double mem_free_limit = total_mem * free_limit_ratio; |
331 | const double mem_free_old_limit = _max_old_gen_size * free_limit_ratio; |
332 | const double mem_free_eden_limit = _max_eden_size * free_limit_ratio; |
333 | size_t promo_limit = (size_t)(_max_old_gen_size - _avg_old_live); |
334 | // But don't force a promo size below the current promo size. Otherwise, |
335 | // the promo size will shrink for no good reason. |
336 | promo_limit = MAX2(promo_limit, _promo_size); |
337 | |
338 | log_trace(gc, ergo)( |
339 | "AdaptiveSizePolicySpaceOverheadTester::is_exceeded:" |
340 | " promo_limit: " SIZE_FORMAT |
341 | " max_eden_size: " SIZE_FORMAT |
342 | " total_free_limit: " SIZE_FORMAT |
343 | " max_old_gen_size: " SIZE_FORMAT |
344 | " max_eden_size: " SIZE_FORMAT |
345 | " mem_free_limit: " SIZE_FORMAT, |
346 | promo_limit, _max_eden_size, total_free_limit, |
347 | _max_old_gen_size, _max_eden_size, |
348 | (size_t)mem_free_limit); |
349 | |
350 | return free_in_old_gen < (size_t)mem_free_old_limit && |
351 | free_in_eden < (size_t)mem_free_eden_limit; |
352 | } |
353 | }; |
354 | |
355 | void AdaptiveSizePolicy::check_gc_overhead_limit( |
356 | size_t eden_live, |
357 | size_t max_old_gen_size, |
358 | size_t max_eden_size, |
359 | bool is_full_gc, |
360 | GCCause::Cause gc_cause, |
361 | SoftRefPolicy* soft_ref_policy) { |
362 | |
363 | AdaptiveSizePolicyTimeOverheadTester time_overhead(gc_cost()); |
364 | AdaptiveSizePolicySpaceOverheadTester space_overhead(eden_live, |
365 | max_old_gen_size, |
366 | max_eden_size, |
367 | _promo_size, |
368 | avg_eden_live()->average(), |
369 | avg_old_live()->average()); |
370 | _overhead_checker.check_gc_overhead_limit(&time_overhead, |
371 | &space_overhead, |
372 | is_full_gc, |
373 | gc_cause, |
374 | soft_ref_policy); |
375 | } |
376 | // Printing |
377 | |
378 | bool AdaptiveSizePolicy::print() const { |
379 | assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled." ); |
380 | |
381 | if (!log_is_enabled(Debug, gc, ergo)) { |
382 | return false; |
383 | } |
384 | |
385 | // Print goal for which action is needed. |
386 | char* action = NULL; |
387 | bool change_for_pause = false; |
388 | if ((change_old_gen_for_maj_pauses() == |
389 | decrease_old_gen_for_maj_pauses_true) || |
390 | (change_young_gen_for_min_pauses() == |
391 | decrease_young_gen_for_min_pauses_true)) { |
392 | action = (char*) " *** pause time goal ***" ; |
393 | change_for_pause = true; |
394 | } else if ((change_old_gen_for_throughput() == |
395 | increase_old_gen_for_throughput_true) || |
396 | (change_young_gen_for_throughput() == |
397 | increase_young_gen_for_througput_true)) { |
398 | action = (char*) " *** throughput goal ***" ; |
399 | } else if (decrease_for_footprint()) { |
400 | action = (char*) " *** reduced footprint ***" ; |
401 | } else { |
402 | // No actions were taken. This can legitimately be the |
403 | // situation if not enough data has been gathered to make |
404 | // decisions. |
405 | return false; |
406 | } |
407 | |
408 | // Pauses |
409 | // Currently the size of the old gen is only adjusted to |
410 | // change the major pause times. |
411 | char* young_gen_action = NULL; |
412 | char* tenured_gen_action = NULL; |
413 | |
414 | char* shrink_msg = (char*) "(attempted to shrink)" ; |
415 | char* grow_msg = (char*) "(attempted to grow)" ; |
416 | char* no_change_msg = (char*) "(no change)" ; |
417 | if (change_young_gen_for_min_pauses() == |
418 | decrease_young_gen_for_min_pauses_true) { |
419 | young_gen_action = shrink_msg; |
420 | } else if (change_for_pause) { |
421 | young_gen_action = no_change_msg; |
422 | } |
423 | |
424 | if (change_old_gen_for_maj_pauses() == decrease_old_gen_for_maj_pauses_true) { |
425 | tenured_gen_action = shrink_msg; |
426 | } else if (change_for_pause) { |
427 | tenured_gen_action = no_change_msg; |
428 | } |
429 | |
430 | // Throughput |
431 | if (change_old_gen_for_throughput() == increase_old_gen_for_throughput_true) { |
432 | assert(change_young_gen_for_throughput() == |
433 | increase_young_gen_for_througput_true, |
434 | "Both generations should be growing" ); |
435 | young_gen_action = grow_msg; |
436 | tenured_gen_action = grow_msg; |
437 | } else if (change_young_gen_for_throughput() == |
438 | increase_young_gen_for_througput_true) { |
439 | // Only the young generation may grow at start up (before |
440 | // enough full collections have been done to grow the old generation). |
441 | young_gen_action = grow_msg; |
442 | tenured_gen_action = no_change_msg; |
443 | } |
444 | |
445 | // Minimum footprint |
446 | if (decrease_for_footprint() != 0) { |
447 | young_gen_action = shrink_msg; |
448 | tenured_gen_action = shrink_msg; |
449 | } |
450 | |
451 | log_debug(gc, ergo)("UseAdaptiveSizePolicy actions to meet %s" , action); |
452 | log_debug(gc, ergo)(" GC overhead (%%)" ); |
453 | log_debug(gc, ergo)(" Young generation: %7.2f\t %s" , |
454 | 100.0 * avg_minor_gc_cost()->average(), young_gen_action); |
455 | log_debug(gc, ergo)(" Tenured generation: %7.2f\t %s" , |
456 | 100.0 * avg_major_gc_cost()->average(), tenured_gen_action); |
457 | return true; |
458 | } |
459 | |
460 | void AdaptiveSizePolicy::print_tenuring_threshold( uint new_tenuring_threshold_arg) const { |
461 | // Tenuring threshold |
462 | if (decrement_tenuring_threshold_for_survivor_limit()) { |
463 | log_debug(gc, ergo)("Tenuring threshold: (attempted to decrease to avoid survivor space overflow) = %u" , new_tenuring_threshold_arg); |
464 | } else if (decrement_tenuring_threshold_for_gc_cost()) { |
465 | log_debug(gc, ergo)("Tenuring threshold: (attempted to decrease to balance GC costs) = %u" , new_tenuring_threshold_arg); |
466 | } else if (increment_tenuring_threshold_for_gc_cost()) { |
467 | log_debug(gc, ergo)("Tenuring threshold: (attempted to increase to balance GC costs) = %u" , new_tenuring_threshold_arg); |
468 | } else { |
469 | assert(!tenuring_threshold_change(), "(no change was attempted)" ); |
470 | } |
471 | } |
472 | |