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
32elapsedTimer AdaptiveSizePolicy::_minor_timer;
33elapsedTimer 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
42AdaptiveSizePolicy::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
85bool 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
91void 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
100void 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
107void 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
158size_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
164size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden) {
165 return eden_increment(cur_eden, YoungGenerationSizeIncrement);
166}
167
168size_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
174size_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
180size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo) {
181 return promo_increment(cur_promo, TenuredGenerationSizeIncrement);
182}
183
184size_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
190double 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
198double 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
237double 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
262void 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
272class 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
283class 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
355void 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
378bool 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
460void 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