# HG changeset patch # User manc # Date 1547596787 28800 # Tue Jan 15 15:59:47 2019 -0800 # Node ID c84ad734e2aed8702159c9f88611b66c65f64672 # Parent 142b179dd60e34c3d4b2f8f53c8687d7a0fb763b 8212206: Refactor AdaptiveSizePolicy to separate out code related to GC overhead Summary: Move check_gc_overhead_limit() and related code to its own class Reviewed-by: diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1498,8 +1498,7 @@ // Has the GC time limit been exceeded? size_t max_eden_size = _young_gen->max_eden_size(); GCCause::Cause gc_cause = heap->gc_cause(); - size_policy()->check_gc_overhead_limit(_young_gen->used(), - _young_gen->eden()->used(), + size_policy()->check_gc_overhead_limit(_young_gen->eden()->used(), _cmsGen->max_capacity(), max_eden_size, full, diff --git a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp --- a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp +++ b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,11 +118,6 @@ _avg_base_footprint = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, (jlong) ps_size_policy()->avg_base_footprint()->average(), CHECK); - cname = PerfDataManager::counter_name(name_space(), "gcTimeLimitExceeded"); - _gc_overhead_limit_exceeded_counter = - PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Events, ps_size_policy()->gc_overhead_limit_exceeded(), CHECK); - cname = PerfDataManager::counter_name(name_space(), "liveAtLastFullGc"); _live_at_last_full_gc_counter = PerfDataManager::create_variable(SUN_GC, cname, diff --git a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp --- a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp +++ b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp @@ -51,7 +51,6 @@ PerfVariable* _live_space; PerfVariable* _free_space; PerfVariable* _avg_base_footprint; - PerfVariable* _gc_overhead_limit_exceeded_counter; PerfVariable* _live_at_last_full_gc_counter; PerfVariable* _old_capacity; PerfVariable* _boundary_moved; @@ -177,7 +176,7 @@ ); } inline void update_gc_overhead_limit_exceeded_counter() { - _gc_overhead_limit_exceeded_counter->set_value( + gc_overhead_limit_exceeded_counter()->set_value( (jlong) ps_size_policy()->gc_overhead_limit_exceeded()); } inline void update_live_at_last_full_gc_counter() { diff --git a/src/hotspot/share/gc/parallel/psMarkSweep.cpp b/src/hotspot/share/gc/parallel/psMarkSweep.cpp --- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp +++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -316,8 +316,7 @@ max_eden_size, true /* full gc*/); - size_policy->check_gc_overhead_limit(young_live, - eden_live, + size_policy->check_gc_overhead_limit(eden_live, max_old_gen_size, max_eden_size, true /* full gc*/, diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1889,8 +1889,7 @@ max_eden_size, true /* full gc*/); - size_policy->check_gc_overhead_limit(young_live, - eden_live, + size_policy->check_gc_overhead_limit(eden_live, max_old_gen_size, max_eden_size, true /* full gc*/, diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -543,8 +543,7 @@ max_eden_size, false /* not full gc*/); - size_policy->check_gc_overhead_limit(young_live, - eden_live, + size_policy->check_gc_overhead_limit(eden_live, max_old_gen_size, max_eden_size, false /* not full gc*/, diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #include "gc/shared/adaptiveSizePolicy.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcUtil.inline.hpp" -#include "gc/shared/softRefPolicy.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" @@ -49,16 +48,11 @@ _eden_size(init_eden_size), _promo_size(init_promo_size), _survivor_size(init_survivor_size), - _gc_overhead_limit_exceeded(false), - _print_gc_overhead_limit_would_be_exceeded(false), - _gc_overhead_limit_count(0), _latest_minor_mutator_interval_seconds(0), _threshold_tolerance_percent(1.0 + ThresholdTolerance/100.0), _gc_pause_goal_sec(gc_pause_goal_sec), _young_gen_change_for_minor_throughput(0), _old_gen_change_for_major_throughput(0) { - assert(AdaptiveSizePolicyGCTimeLimitThreshold > 0, - "No opportunity to clear SoftReferences before GC overhead limit"); _avg_minor_pause = new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding); _avg_minor_interval = new AdaptiveWeightedAverage(AdaptiveTimeWeight); @@ -277,8 +271,95 @@ set_decide_at_full_gc(0); } +class AdaptiveSizePolicyTimeOverheadTester: public GCOverheadTester { + double _gc_cost; + + public: + AdaptiveSizePolicyTimeOverheadTester(double gc_cost) : _gc_cost(gc_cost) {} + + bool is_exceeded() { + // Note that the gc time limit test only works for the collections + // of the young gen + tenured gen and not for collections of the + // permanent gen. That is because the calculation of the space + // freed by the collection is the free space in the young gen + + // tenured gen. + return _gc_cost > (GCTimeLimit / 100.0); + } +}; + +class AdaptiveSizePolicySpaceOverheadTester: public GCOverheadTester { + size_t _eden_live; + size_t _max_old_gen_size; + size_t _max_eden_size; + size_t _promo_size; + double _avg_eden_live; + double _avg_old_live; + + public: + AdaptiveSizePolicySpaceOverheadTester(size_t eden_live, + size_t max_old_gen_size, + size_t max_eden_size, + size_t promo_size, + double avg_eden_live, + double avg_old_live) : + _eden_live(eden_live), + _max_old_gen_size(max_old_gen_size), + _max_eden_size(max_eden_size), + _promo_size(promo_size), + _avg_eden_live(avg_eden_live), + _avg_old_live(avg_old_live) {} + + bool is_exceeded() { + // _max_eden_size is the upper limit on the size of eden based on + // the maximum size of the young generation and the sizes + // of the survivor space. + // The question being asked is whether the space being recovered by + // a collection is low. + // free_in_eden is the free space in eden after a collection and + // free_in_old_gen is the free space in the old generation after + // a collection. + // + // Use the minimum of the current value of the live in eden + // or the average of the live in eden. + // If the current value drops quickly, that should be taken + // into account (i.e., don't trigger if the amount of free + // space has suddenly jumped up). If the current is much + // higher than the average, use the average since it represents + // the longer term behavior. + const size_t live_in_eden = + MIN2(_eden_live, (size_t)_avg_eden_live); + const size_t free_in_eden = _max_eden_size > live_in_eden ? + _max_eden_size - live_in_eden : 0; + const size_t free_in_old_gen = (size_t)(_max_old_gen_size - _avg_old_live); + const size_t total_free_limit = free_in_old_gen + free_in_eden; + const size_t total_mem = _max_old_gen_size + _max_eden_size; + const double free_limit_ratio = GCHeapFreeLimit / 100.0; + const double mem_free_limit = total_mem * free_limit_ratio; + const double mem_free_old_limit = _max_old_gen_size * free_limit_ratio; + const double mem_free_eden_limit = _max_eden_size * free_limit_ratio; + size_t promo_limit = (size_t)(_max_old_gen_size - _avg_old_live); + // But don't force a promo size below the current promo size. Otherwise, + // the promo size will shrink for no good reason. + promo_limit = MAX2(promo_limit, _promo_size); + + log_trace(gc, ergo)( + "AdaptiveSizePolicySpaceOverheadTester::is_exceeded:" + " promo_limit: " SIZE_FORMAT + " max_eden_size: " SIZE_FORMAT + " total_free_limit: " SIZE_FORMAT + " max_old_gen_size: " SIZE_FORMAT + " max_eden_size: " SIZE_FORMAT + " mem_free_limit: " SIZE_FORMAT, + promo_limit, _max_eden_size, total_free_limit, + _max_old_gen_size, _max_eden_size, + (size_t)mem_free_limit); + + return free_in_old_gen < (size_t)mem_free_old_limit && + free_in_eden < (size_t)mem_free_eden_limit; + } +}; + void AdaptiveSizePolicy::check_gc_overhead_limit( - size_t young_live, size_t eden_live, size_t max_old_gen_size, size_t max_eden_size, @@ -286,128 +367,18 @@ GCCause::Cause gc_cause, SoftRefPolicy* soft_ref_policy) { - // Ignore explicit GC's. Exiting here does not set the flag and - // does not reset the count. Updating of the averages for system - // GC's is still controlled by UseAdaptiveSizePolicyWithSystemGC. - if (GCCause::is_user_requested_gc(gc_cause) || - GCCause::is_serviceability_requested_gc(gc_cause)) { - return; - } - // eden_limit is the upper limit on the size of eden based on - // the maximum size of the young generation and the sizes - // of the survivor space. - // The question being asked is whether the gc costs are high - // and the space being recovered by a collection is low. - // free_in_young_gen is the free space in the young generation - // after a collection and promo_live is the free space in the old - // generation after a collection. - // - // Use the minimum of the current value of the live in the - // young gen or the average of the live in the young gen. - // If the current value drops quickly, that should be taken - // into account (i.e., don't trigger if the amount of free - // space has suddenly jumped up). If the current is much - // higher than the average, use the average since it represents - // the longer term behavior. - const size_t live_in_eden = - MIN2(eden_live, (size_t) avg_eden_live()->average()); - const size_t free_in_eden = max_eden_size > live_in_eden ? - max_eden_size - live_in_eden : 0; - const size_t free_in_old_gen = (size_t)(max_old_gen_size - avg_old_live()->average()); - const size_t total_free_limit = free_in_old_gen + free_in_eden; - const size_t total_mem = max_old_gen_size + max_eden_size; - const double mem_free_limit = total_mem * (GCHeapFreeLimit/100.0); - const double mem_free_old_limit = max_old_gen_size * (GCHeapFreeLimit/100.0); - const double mem_free_eden_limit = max_eden_size * (GCHeapFreeLimit/100.0); - const double gc_cost_limit = GCTimeLimit/100.0; - size_t promo_limit = (size_t)(max_old_gen_size - avg_old_live()->average()); - // But don't force a promo size below the current promo size. Otherwise, - // the promo size will shrink for no good reason. - promo_limit = MAX2(promo_limit, _promo_size); - - - log_trace(gc, ergo)( - "PSAdaptiveSizePolicy::check_gc_overhead_limit:" - " promo_limit: " SIZE_FORMAT - " max_eden_size: " SIZE_FORMAT - " total_free_limit: " SIZE_FORMAT - " max_old_gen_size: " SIZE_FORMAT - " max_eden_size: " SIZE_FORMAT - " mem_free_limit: " SIZE_FORMAT, - promo_limit, max_eden_size, total_free_limit, - max_old_gen_size, max_eden_size, - (size_t) mem_free_limit); - - bool print_gc_overhead_limit_would_be_exceeded = false; - if (is_full_gc) { - if (gc_cost() > gc_cost_limit && - free_in_old_gen < (size_t) mem_free_old_limit && - free_in_eden < (size_t) mem_free_eden_limit) { - // Collections, on average, are taking too much time, and - // gc_cost() > gc_cost_limit - // we have too little space available after a full gc. - // total_free_limit < mem_free_limit - // where - // total_free_limit is the free space available in - // both generations - // total_mem is the total space available for allocation - // in both generations (survivor spaces are not included - // just as they are not included in eden_limit). - // mem_free_limit is a fraction of total_mem judged to be an - // acceptable amount that is still unused. - // The heap can ask for the value of this variable when deciding - // whether to thrown an OutOfMemory error. - // Note that the gc time limit test only works for the collections - // of the young gen + tenured gen and not for collections of the - // permanent gen. That is because the calculation of the space - // freed by the collection is the free space in the young gen + - // tenured gen. - // At this point the GC overhead limit is being exceeded. - inc_gc_overhead_limit_count(); - if (UseGCOverheadLimit) { - if (gc_overhead_limit_count() >= - AdaptiveSizePolicyGCTimeLimitThreshold){ - // All conditions have been met for throwing an out-of-memory - set_gc_overhead_limit_exceeded(true); - // Avoid consecutive OOM due to the gc time limit by resetting - // the counter. - reset_gc_overhead_limit_count(); - } else { - // The required consecutive collections which exceed the - // GC time limit may or may not have been reached. We - // are approaching that condition and so as not to - // throw an out-of-memory before all SoftRef's have been - // cleared, set _should_clear_all_soft_refs in CollectorPolicy. - // The clearing will be done on the next GC. - bool near_limit = gc_overhead_limit_near(); - if (near_limit) { - soft_ref_policy->set_should_clear_all_soft_refs(true); - log_trace(gc, ergo)("Nearing GC overhead limit, will be clearing all SoftReference"); - } - } - } - // Set this even when the overhead limit will not - // cause an out-of-memory. Diagnostic message indicating - // that the overhead limit is being exceeded is sometimes - // printed. - print_gc_overhead_limit_would_be_exceeded = true; - - } else { - // Did not exceed overhead limits - reset_gc_overhead_limit_count(); - } - } - - if (UseGCOverheadLimit) { - if (gc_overhead_limit_exceeded()) { - log_trace(gc, ergo)("GC is exceeding overhead limit of " UINTX_FORMAT "%%", GCTimeLimit); - reset_gc_overhead_limit_count(); - } else if (print_gc_overhead_limit_would_be_exceeded) { - assert(gc_overhead_limit_count() > 0, "Should not be printing"); - log_trace(gc, ergo)("GC would exceed overhead limit of " UINTX_FORMAT "%% %d consecutive time(s)", - GCTimeLimit, gc_overhead_limit_count()); - } - } + AdaptiveSizePolicyTimeOverheadTester time_overhead(gc_cost()); + AdaptiveSizePolicySpaceOverheadTester space_overhead(eden_live, + max_old_gen_size, + max_eden_size, + _promo_size, + avg_eden_live()->average(), + avg_old_live()->average()); + _overhead_checker.check_gc_overhead_limit(&time_overhead, + &space_overhead, + is_full_gc, + gc_cause, + soft_ref_policy); } // Printing diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_SHARED_ADAPTIVESIZEPOLICY_HPP #include "gc/shared/gcCause.hpp" +#include "gc/shared/gcOverheadChecker.hpp" #include "gc/shared/gcUtil.hpp" #include "memory/allocation.hpp" @@ -34,7 +35,6 @@ // Forward decls class elapsedTimer; -class SoftRefPolicy; class AdaptiveSizePolicy : public CHeapObj { friend class GCAdaptivePolicyCounters; @@ -81,18 +81,8 @@ size_t _survivor_size; // calculated survivor size in bytes - // This is a hint for the heap: we've detected that GC times - // are taking longer than GCTimeLimit allows. - bool _gc_overhead_limit_exceeded; - // Use for diagnostics only. If UseGCOverheadLimit is false, - // this variable is still set. - bool _print_gc_overhead_limit_would_be_exceeded; - // Count of consecutive GC that have exceeded the - // GC time limit criterion - uint _gc_overhead_limit_count; - // This flag signals that GCTimeLimit is being exceeded - // but may not have done so for the required number of consecutive - // collections + // Support for UseGCOverheadLimit + GCOverheadChecker _overhead_checker; // Minor collection timers used to determine both // pause and interval times for collections @@ -412,26 +402,20 @@ return _survivor_size; } - // This is a hint for the heap: we've detected that gc times - // are taking longer than GCTimeLimit allows. - // Most heaps will choose to throw an OutOfMemoryError when - // this occurs but it is up to the heap to request this information - // of the policy bool gc_overhead_limit_exceeded() { - return _gc_overhead_limit_exceeded; + return _overhead_checker.gc_overhead_limit_exceeded(); } void set_gc_overhead_limit_exceeded(bool v) { - _gc_overhead_limit_exceeded = v; + _overhead_checker.set_gc_overhead_limit_exceeded(v); } - // Tests conditions indicate the GC overhead limit is being approached. bool gc_overhead_limit_near() { - return gc_overhead_limit_count() >= - (AdaptiveSizePolicyGCTimeLimitThreshold - 1); + return _overhead_checker.gc_overhead_limit_near(); } - uint gc_overhead_limit_count() { return _gc_overhead_limit_count; } - void reset_gc_overhead_limit_count() { _gc_overhead_limit_count = 0; } - void inc_gc_overhead_limit_count() { _gc_overhead_limit_count++; } + + void reset_gc_overhead_limit_count() { + _overhead_checker.reset_gc_overhead_limit_count(); + } // accessors for flags recording the decisions to resize the // generations to meet the pause goal. @@ -448,8 +432,7 @@ // Check the conditions for an out-of-memory due to excessive GC time. // Set _gc_overhead_limit_exceeded if all the conditions have been met. - void check_gc_overhead_limit(size_t young_live, - size_t eden_live, + void check_gc_overhead_limit(size_t eden_live, size_t max_old_gen_size, size_t max_eden_size, bool is_full_gc, diff --git a/src/hotspot/share/gc/shared/gcOverheadChecker.cpp b/src/hotspot/share/gc/shared/gcOverheadChecker.cpp new file mode 100644 --- /dev/null +++ b/src/hotspot/share/gc/shared/gcOverheadChecker.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/gcOverheadChecker.hpp" +#include "gc/shared/softRefPolicy.hpp" +#include "logging/log.hpp" + +GCOverheadChecker::GCOverheadChecker() : + _gc_overhead_limit_exceeded(false), + _print_gc_overhead_limit_would_be_exceeded(false), + _gc_overhead_limit_count(0) { + assert(GCOverheadLimitThreshold > 0, + "No opportunity to clear SoftReferences before GC overhead limit"); +} + +void GCOverheadChecker::check_gc_overhead_limit(GCOverheadTester* time_overhead, + GCOverheadTester* space_overhead, + bool is_full_gc, + GCCause::Cause gc_cause, + SoftRefPolicy* soft_ref_policy) { + + // Ignore explicit GC's. Exiting here does not set the flag and + // does not reset the count. + if (GCCause::is_user_requested_gc(gc_cause) || + GCCause::is_serviceability_requested_gc(gc_cause)) { + return; + } + + bool print_gc_overhead_limit_would_be_exceeded = false; + if (is_full_gc) { + if (time_overhead->is_exceeded() && space_overhead->is_exceeded()) { + // Collections, on average, are taking too much time, and + // we have too little space available after a full gc. + // At this point the GC overhead limit is being exceeded. + _gc_overhead_limit_count++; + if (UseGCOverheadLimit) { + if (_gc_overhead_limit_count >= GCOverheadLimitThreshold){ + // All conditions have been met for throwing an out-of-memory + set_gc_overhead_limit_exceeded(true); + // Avoid consecutive OOM due to the gc time limit by resetting + // the counter. + reset_gc_overhead_limit_count(); + } else { + // The required consecutive collections which exceed the + // GC time limit may or may not have been reached. We + // are approaching that condition and so as not to + // throw an out-of-memory before all SoftRef's have been + // cleared, set _should_clear_all_soft_refs in CollectorPolicy. + // The clearing will be done on the next GC. + bool near_limit = gc_overhead_limit_near(); + if (near_limit) { + soft_ref_policy->set_should_clear_all_soft_refs(true); + log_trace(gc, ergo)("Nearing GC overhead limit, will be clearing all SoftReference"); + } + } + } + // Set this even when the overhead limit will not + // cause an out-of-memory. Diagnostic message indicating + // that the overhead limit is being exceeded is sometimes + // printed. + print_gc_overhead_limit_would_be_exceeded = true; + + } else { + // Did not exceed overhead limits + reset_gc_overhead_limit_count(); + } + } + + if (UseGCOverheadLimit) { + if (gc_overhead_limit_exceeded()) { + log_trace(gc, ergo)("GC is exceeding overhead limit of " UINTX_FORMAT "%%", GCTimeLimit); + reset_gc_overhead_limit_count(); + } else if (print_gc_overhead_limit_would_be_exceeded) { + assert(_gc_overhead_limit_count > 0, "Should not be printing"); + log_trace(gc, ergo)("GC would exceed overhead limit of " UINTX_FORMAT "%% %d consecutive time(s)", + GCTimeLimit, _gc_overhead_limit_count); + } + } +} diff --git a/src/hotspot/share/gc/shared/gcOverheadChecker.hpp b/src/hotspot/share/gc/shared/gcOverheadChecker.hpp new file mode 100644 --- /dev/null +++ b/src/hotspot/share/gc/shared/gcOverheadChecker.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_GCOVERHEADCHECKER_HPP +#define SHARE_GC_SHARED_GCOVERHEADCHECKER_HPP + +#include "memory/allocation.hpp" +#include "gc/shared/gcCause.hpp" + +class SoftRefPolicy; + +class GCOverheadTester: public StackObj { +public: + virtual bool is_exceeded() = 0; +}; + +class GCOverheadChecker: public CHeapObj { + // This is a hint for the heap: we've detected that GC times + // are taking longer than GCTimeLimit allows. + bool _gc_overhead_limit_exceeded; + // Use for diagnostics only. If UseGCOverheadLimit is false, + // this variable is still set. + bool _print_gc_overhead_limit_would_be_exceeded; + // Count of consecutive GC that have exceeded the + // GC time limit criterion + uint _gc_overhead_limit_count; + // This flag signals that GCTimeLimit is being exceeded + // but may not have done so for the required number of consecutive + // collections + +public: + GCOverheadChecker(); + + // This is a hint for the heap: we've detected that gc times + // are taking longer than GCTimeLimit allows. + // Most heaps will choose to throw an OutOfMemoryError when + // this occurs but it is up to the heap to request this information + // of the policy + bool gc_overhead_limit_exceeded() { + return _gc_overhead_limit_exceeded; + } + void set_gc_overhead_limit_exceeded(bool v) { + _gc_overhead_limit_exceeded = v; + } + + // Tests conditions indicate the GC overhead limit is being approached. + bool gc_overhead_limit_near() { + return _gc_overhead_limit_count >= (GCOverheadLimitThreshold - 1); + } + void reset_gc_overhead_limit_count() { + _gc_overhead_limit_count = 0; + } + + // Check the conditions for an out-of-memory due to excessive GC time. + // Set _gc_overhead_limit_exceeded if all the conditions have been met. + void check_gc_overhead_limit(GCOverheadTester* time_overhead, + GCOverheadTester* space_overhead, + bool is_full_gc, + GCCause::Cause gc_cause, + SoftRefPolicy* soft_ref_policy); +}; + +#endif // SHARE_GC_SHARED_GCOVERHEADCHECKER_HPP diff --git a/src/hotspot/share/gc/shared/gcPolicyCounters.cpp b/src/hotspot/share/gc/shared/gcPolicyCounters.cpp --- a/src/hotspot/share/gc/shared/gcPolicyCounters.cpp +++ b/src/hotspot/share/gc/shared/gcPolicyCounters.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,5 +59,10 @@ _desired_survivor_size = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK); + + cname = PerfDataManager::counter_name(_name_space, "gcTimeLimitExceeded"); + _gc_overhead_limit_exceeded_counter = + PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Events, + CHECK); } } diff --git a/src/hotspot/share/gc/shared/gcPolicyCounters.hpp b/src/hotspot/share/gc/shared/gcPolicyCounters.hpp --- a/src/hotspot/share/gc/shared/gcPolicyCounters.hpp +++ b/src/hotspot/share/gc/shared/gcPolicyCounters.hpp @@ -41,6 +41,7 @@ PerfVariable* _tenuring_threshold; PerfVariable* _desired_survivor_size; + PerfVariable* _gc_overhead_limit_exceeded_counter; const char* _name_space; @@ -62,6 +63,10 @@ return _desired_survivor_size; } + inline PerfVariable* gc_overhead_limit_exceeded_counter() const { + return _gc_overhead_limit_exceeded_counter; + } + const char* name_space() const { return _name_space; } virtual void update_counters() {} diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -616,7 +616,7 @@ "OutOfMemoryError is thrown (used with GCTimeLimit)") \ range(0, 100) \ \ - develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \ + develop(uintx, GCOverheadLimitThreshold, 5, \ "Number of consecutive collections before gc time limit fires") \ range(1, max_uintx) \ \