Path: blob/master/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp
40957 views
/*1* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "gc/shared/adaptiveSizePolicy.hpp"26#include "gc/shared/gcCause.hpp"27#include "gc/shared/gcUtil.inline.hpp"28#include "logging/log.hpp"29#include "runtime/timer.hpp"3031elapsedTimer AdaptiveSizePolicy::_minor_timer;32elapsedTimer AdaptiveSizePolicy::_major_timer;3334// The throughput goal is implemented as35// _throughput_goal = 1 - ( 1 / (1 + gc_cost_ratio))36// gc_cost_ratio is the ratio37// application cost / gc cost38// For example a gc_cost_ratio of 4 translates into a39// throughput goal of .804041AdaptiveSizePolicy::AdaptiveSizePolicy(size_t init_eden_size,42size_t init_promo_size,43size_t init_survivor_size,44double gc_pause_goal_sec,45uint gc_cost_ratio) :46_throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))),47_eden_size(init_eden_size),48_promo_size(init_promo_size),49_survivor_size(init_survivor_size),50_avg_minor_pause(new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding)),51_avg_minor_interval(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),52_avg_minor_gc_cost(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),53_avg_major_interval(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),54_avg_major_gc_cost(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),55_avg_young_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),56_avg_eden_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),57_avg_old_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),58_avg_survived(new AdaptivePaddedAverage(AdaptiveSizePolicyWeight, SurvivorPadding)),59_avg_pretenured(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, SurvivorPadding)),60_minor_pause_old_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),61_minor_pause_young_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),62_minor_collection_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),63_major_collection_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),64_latest_minor_mutator_interval_seconds(0),65_threshold_tolerance_percent(1.0 + ThresholdTolerance/100.0),66_gc_pause_goal_sec(gc_pause_goal_sec),67_young_gen_policy_is_ready(false),68_change_young_gen_for_min_pauses(0),69_change_old_gen_for_maj_pauses(0),70_change_old_gen_for_throughput(0),71_change_young_gen_for_throughput(0),72_increment_tenuring_threshold_for_gc_cost(false),73_decrement_tenuring_threshold_for_gc_cost(false),74_decrement_tenuring_threshold_for_survivor_limit(false),75_decrease_for_footprint(0),76_decide_at_full_gc(0),77_young_gen_change_for_minor_throughput(0),78_old_gen_change_for_major_throughput(0) {7980// Start the timers81_minor_timer.start();82}8384bool AdaptiveSizePolicy::tenuring_threshold_change() const {85return decrement_tenuring_threshold_for_gc_cost() ||86increment_tenuring_threshold_for_gc_cost() ||87decrement_tenuring_threshold_for_survivor_limit();88}8990void AdaptiveSizePolicy::minor_collection_begin() {91// Update the interval time92_minor_timer.stop();93// Save most recent collection time94_latest_minor_mutator_interval_seconds = _minor_timer.seconds();95_minor_timer.reset();96_minor_timer.start();97}9899void AdaptiveSizePolicy::update_minor_pause_young_estimator(100double minor_pause_in_ms) {101double eden_size_in_mbytes = ((double)_eden_size)/((double)M);102_minor_pause_young_estimator->update(eden_size_in_mbytes,103minor_pause_in_ms);104}105106void AdaptiveSizePolicy::minor_collection_end(GCCause::Cause gc_cause) {107// Update the pause time.108_minor_timer.stop();109110if (!GCCause::is_user_requested_gc(gc_cause) ||111UseAdaptiveSizePolicyWithSystemGC) {112double minor_pause_in_seconds = _minor_timer.seconds();113double minor_pause_in_ms = minor_pause_in_seconds * MILLIUNITS;114115// Sample for performance counter116_avg_minor_pause->sample(minor_pause_in_seconds);117118// Cost of collection (unit-less)119double collection_cost = 0.0;120if ((_latest_minor_mutator_interval_seconds > 0.0) &&121(minor_pause_in_seconds > 0.0)) {122double interval_in_seconds =123_latest_minor_mutator_interval_seconds + minor_pause_in_seconds;124collection_cost =125minor_pause_in_seconds / interval_in_seconds;126_avg_minor_gc_cost->sample(collection_cost);127// Sample for performance counter128_avg_minor_interval->sample(interval_in_seconds);129}130131// The policy does not have enough data until at least some132// young collections have been done.133_young_gen_policy_is_ready =134(_avg_minor_gc_cost->count() >= AdaptiveSizePolicyReadyThreshold);135136// Calculate variables used to estimate pause time vs. gen sizes137double eden_size_in_mbytes = ((double)_eden_size) / ((double)M);138update_minor_pause_young_estimator(minor_pause_in_ms);139update_minor_pause_old_estimator(minor_pause_in_ms);140141log_trace(gc, ergo)("AdaptiveSizePolicy::minor_collection_end: minor gc cost: %f average: %f",142collection_cost, _avg_minor_gc_cost->average());143log_trace(gc, ergo)(" minor pause: %f minor period %f",144minor_pause_in_ms, _latest_minor_mutator_interval_seconds * MILLIUNITS);145146// Calculate variable used to estimate collection cost vs. gen sizes147assert(collection_cost >= 0.0, "Expected to be non-negative");148_minor_collection_estimator->update(eden_size_in_mbytes, collection_cost);149}150151// Interval times use this timer to measure the mutator time.152// Reset the timer after the GC pause.153_minor_timer.reset();154_minor_timer.start();155}156157size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden, uint percent_change) {158size_t eden_heap_delta;159eden_heap_delta = cur_eden / 100 * percent_change;160return eden_heap_delta;161}162163size_t AdaptiveSizePolicy::eden_increment(size_t cur_eden) {164return eden_increment(cur_eden, YoungGenerationSizeIncrement);165}166167size_t AdaptiveSizePolicy::eden_decrement(size_t cur_eden) {168size_t eden_heap_delta = eden_increment(cur_eden) /169AdaptiveSizeDecrementScaleFactor;170return eden_heap_delta;171}172173size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo, uint percent_change) {174size_t promo_heap_delta;175promo_heap_delta = cur_promo / 100 * percent_change;176return promo_heap_delta;177}178179size_t AdaptiveSizePolicy::promo_increment(size_t cur_promo) {180return promo_increment(cur_promo, TenuredGenerationSizeIncrement);181}182183size_t AdaptiveSizePolicy::promo_decrement(size_t cur_promo) {184size_t promo_heap_delta = promo_increment(cur_promo);185promo_heap_delta = promo_heap_delta / AdaptiveSizeDecrementScaleFactor;186return promo_heap_delta;187}188189double AdaptiveSizePolicy::time_since_major_gc() const {190_major_timer.stop();191double result = _major_timer.seconds();192_major_timer.start();193return result;194}195196// Linear decay of major gc cost197double AdaptiveSizePolicy::decaying_major_gc_cost() const {198double major_interval = major_gc_interval_average_for_decay();199double major_gc_cost_average = major_gc_cost();200double decayed_major_gc_cost = major_gc_cost_average;201if(time_since_major_gc() > 0.0) {202decayed_major_gc_cost = major_gc_cost() *203(((double) AdaptiveSizeMajorGCDecayTimeScale) * major_interval)204/ time_since_major_gc();205}206207// The decayed cost should always be smaller than the208// average cost but the vagaries of finite arithmetic could209// produce a larger value in decayed_major_gc_cost so protect210// against that.211return MIN2(major_gc_cost_average, decayed_major_gc_cost);212}213214// Use a value of the major gc cost that has been decayed215// by the factor216//217// average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale /218// time-since-last-major-gc219//220// if the average-interval-between-major-gc * AdaptiveSizeMajorGCDecayTimeScale221// is less than time-since-last-major-gc.222//223// In cases where there are initial major gc's that224// are of a relatively high cost but no later major225// gc's, the total gc cost can remain high because226// the major gc cost remains unchanged (since there are no major227// gc's). In such a situation the value of the unchanging228// major gc cost can keep the mutator throughput below229// the goal when in fact the major gc cost is becoming diminishingly230// small. Use the decaying gc cost only to decide whether to231// adjust for throughput. Using it also to determine the adjustment232// to be made for throughput also seems reasonable but there is233// no test case to use to decide if it is the right thing to do234// don't do it yet.235236double AdaptiveSizePolicy::decaying_gc_cost() const {237double decayed_major_gc_cost = major_gc_cost();238double avg_major_interval = major_gc_interval_average_for_decay();239if (UseAdaptiveSizeDecayMajorGCCost &&240(AdaptiveSizeMajorGCDecayTimeScale > 0) &&241(avg_major_interval > 0.00)) {242double time_since_last_major_gc = time_since_major_gc();243244// Decay the major gc cost?245if (time_since_last_major_gc >246((double) AdaptiveSizeMajorGCDecayTimeScale) * avg_major_interval) {247248// Decay using the time-since-last-major-gc249decayed_major_gc_cost = decaying_major_gc_cost();250log_trace(gc, ergo)("decaying_gc_cost: major interval average: %f time since last major gc: %f",251avg_major_interval, time_since_last_major_gc);252log_trace(gc, ergo)(" major gc cost: %f decayed major gc cost: %f",253major_gc_cost(), decayed_major_gc_cost);254}255}256double result = MIN2(1.0, decayed_major_gc_cost + minor_gc_cost());257return result;258}259260261void AdaptiveSizePolicy::clear_generation_free_space_flags() {262set_change_young_gen_for_min_pauses(0);263set_change_old_gen_for_maj_pauses(0);264265set_change_old_gen_for_throughput(0);266set_change_young_gen_for_throughput(0);267set_decrease_for_footprint(0);268set_decide_at_full_gc(0);269}270271class AdaptiveSizePolicyTimeOverheadTester: public GCOverheadTester {272double _gc_cost;273274public:275AdaptiveSizePolicyTimeOverheadTester(double gc_cost) : _gc_cost(gc_cost) {}276277bool is_exceeded() {278return _gc_cost > (GCTimeLimit / 100.0);279}280};281282class AdaptiveSizePolicySpaceOverheadTester: public GCOverheadTester {283size_t _eden_live;284size_t _max_old_gen_size;285size_t _max_eden_size;286size_t _promo_size;287double _avg_eden_live;288double _avg_old_live;289290public:291AdaptiveSizePolicySpaceOverheadTester(size_t eden_live,292size_t max_old_gen_size,293size_t max_eden_size,294size_t promo_size,295double avg_eden_live,296double avg_old_live) :297_eden_live(eden_live),298_max_old_gen_size(max_old_gen_size),299_max_eden_size(max_eden_size),300_promo_size(promo_size),301_avg_eden_live(avg_eden_live),302_avg_old_live(avg_old_live) {}303304bool is_exceeded() {305// _max_eden_size is the upper limit on the size of eden based on306// the maximum size of the young generation and the sizes307// of the survivor space.308// The question being asked is whether the space being recovered by309// a collection is low.310// free_in_eden is the free space in eden after a collection and311// free_in_old_gen is the free space in the old generation after312// a collection.313//314// Use the minimum of the current value of the live in eden315// or the average of the live in eden.316// If the current value drops quickly, that should be taken317// into account (i.e., don't trigger if the amount of free318// space has suddenly jumped up). If the current is much319// higher than the average, use the average since it represents320// the longer term behavior.321const size_t live_in_eden =322MIN2(_eden_live, (size_t)_avg_eden_live);323const size_t free_in_eden = _max_eden_size > live_in_eden ?324_max_eden_size - live_in_eden : 0;325const size_t free_in_old_gen = (size_t)(_max_old_gen_size - _avg_old_live);326const size_t total_free_limit = free_in_old_gen + free_in_eden;327const size_t total_mem = _max_old_gen_size + _max_eden_size;328const double free_limit_ratio = GCHeapFreeLimit / 100.0;329const double mem_free_limit = total_mem * free_limit_ratio;330const double mem_free_old_limit = _max_old_gen_size * free_limit_ratio;331const double mem_free_eden_limit = _max_eden_size * free_limit_ratio;332size_t promo_limit = (size_t)(_max_old_gen_size - _avg_old_live);333// But don't force a promo size below the current promo size. Otherwise,334// the promo size will shrink for no good reason.335promo_limit = MAX2(promo_limit, _promo_size);336337log_trace(gc, ergo)(338"AdaptiveSizePolicySpaceOverheadTester::is_exceeded:"339" promo_limit: " SIZE_FORMAT340" max_eden_size: " SIZE_FORMAT341" total_free_limit: " SIZE_FORMAT342" max_old_gen_size: " SIZE_FORMAT343" max_eden_size: " SIZE_FORMAT344" mem_free_limit: " SIZE_FORMAT,345promo_limit, _max_eden_size, total_free_limit,346_max_old_gen_size, _max_eden_size,347(size_t)mem_free_limit);348349return free_in_old_gen < (size_t)mem_free_old_limit &&350free_in_eden < (size_t)mem_free_eden_limit;351}352};353354void AdaptiveSizePolicy::check_gc_overhead_limit(355size_t eden_live,356size_t max_old_gen_size,357size_t max_eden_size,358bool is_full_gc,359GCCause::Cause gc_cause,360SoftRefPolicy* soft_ref_policy) {361362AdaptiveSizePolicyTimeOverheadTester time_overhead(gc_cost());363AdaptiveSizePolicySpaceOverheadTester space_overhead(eden_live,364max_old_gen_size,365max_eden_size,366_promo_size,367avg_eden_live()->average(),368avg_old_live()->average());369_overhead_checker.check_gc_overhead_limit(&time_overhead,370&space_overhead,371is_full_gc,372gc_cause,373soft_ref_policy);374}375// Printing376377bool AdaptiveSizePolicy::print() const {378assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled.");379380if (!log_is_enabled(Debug, gc, ergo)) {381return false;382}383384// Print goal for which action is needed.385char* action = NULL;386bool change_for_pause = false;387if ((change_old_gen_for_maj_pauses() ==388decrease_old_gen_for_maj_pauses_true) ||389(change_young_gen_for_min_pauses() ==390decrease_young_gen_for_min_pauses_true)) {391action = (char*) " *** pause time goal ***";392change_for_pause = true;393} else if ((change_old_gen_for_throughput() ==394increase_old_gen_for_throughput_true) ||395(change_young_gen_for_throughput() ==396increase_young_gen_for_througput_true)) {397action = (char*) " *** throughput goal ***";398} else if (decrease_for_footprint()) {399action = (char*) " *** reduced footprint ***";400} else {401// No actions were taken. This can legitimately be the402// situation if not enough data has been gathered to make403// decisions.404return false;405}406407// Pauses408// Currently the size of the old gen is only adjusted to409// change the major pause times.410char* young_gen_action = NULL;411char* tenured_gen_action = NULL;412413char* shrink_msg = (char*) "(attempted to shrink)";414char* grow_msg = (char*) "(attempted to grow)";415char* no_change_msg = (char*) "(no change)";416if (change_young_gen_for_min_pauses() ==417decrease_young_gen_for_min_pauses_true) {418young_gen_action = shrink_msg;419} else if (change_for_pause) {420young_gen_action = no_change_msg;421}422423if (change_old_gen_for_maj_pauses() == decrease_old_gen_for_maj_pauses_true) {424tenured_gen_action = shrink_msg;425} else if (change_for_pause) {426tenured_gen_action = no_change_msg;427}428429// Throughput430if (change_old_gen_for_throughput() == increase_old_gen_for_throughput_true) {431assert(change_young_gen_for_throughput() ==432increase_young_gen_for_througput_true,433"Both generations should be growing");434young_gen_action = grow_msg;435tenured_gen_action = grow_msg;436} else if (change_young_gen_for_throughput() ==437increase_young_gen_for_througput_true) {438// Only the young generation may grow at start up (before439// enough full collections have been done to grow the old generation).440young_gen_action = grow_msg;441tenured_gen_action = no_change_msg;442}443444// Minimum footprint445if (decrease_for_footprint() != 0) {446young_gen_action = shrink_msg;447tenured_gen_action = shrink_msg;448}449450log_debug(gc, ergo)("UseAdaptiveSizePolicy actions to meet %s", action);451log_debug(gc, ergo)(" GC overhead (%%)");452log_debug(gc, ergo)(" Young generation: %7.2f\t %s",453100.0 * avg_minor_gc_cost()->average(), young_gen_action);454log_debug(gc, ergo)(" Tenured generation: %7.2f\t %s",455100.0 * avg_major_gc_cost()->average(), tenured_gen_action);456return true;457}458459void AdaptiveSizePolicy::print_tenuring_threshold( uint new_tenuring_threshold_arg) const {460// Tenuring threshold461if (decrement_tenuring_threshold_for_survivor_limit()) {462log_debug(gc, ergo)("Tenuring threshold: (attempted to decrease to avoid survivor space overflow) = %u", new_tenuring_threshold_arg);463} else if (decrement_tenuring_threshold_for_gc_cost()) {464log_debug(gc, ergo)("Tenuring threshold: (attempted to decrease to balance GC costs) = %u", new_tenuring_threshold_arg);465} else if (increment_tenuring_threshold_for_gc_cost()) {466log_debug(gc, ergo)("Tenuring threshold: (attempted to increase to balance GC costs) = %u", new_tenuring_threshold_arg);467} else {468assert(!tenuring_threshold_change(), "(no change was attempted)");469}470}471472473