< prev index next >

src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp

Print this page
rev 53341 : 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:

@@ -1,7 +1,7 @@
 /*
- * 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -24,11 +24,10 @@
 
 #include "precompiled.hpp"
 #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"
 
 elapsedTimer AdaptiveSizePolicy::_minor_timer;
 elapsedTimer AdaptiveSizePolicy::_major_timer;

@@ -47,20 +46,15 @@
                                        uint gc_cost_ratio) :
     _throughput_goal(1.0 - double(1.0 / (1.0 + (double) gc_cost_ratio))),
     _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);
   _avg_minor_gc_cost  = new AdaptiveWeightedAverage(AdaptiveTimeWeight);
   _avg_major_gc_cost  = new AdaptiveWeightedAverage(AdaptiveTimeWeight);

@@ -275,141 +269,118 @@
   set_change_young_gen_for_throughput(0);
   set_decrease_for_footprint(0);
   set_decide_at_full_gc(0);
 }
 
-void AdaptiveSizePolicy::check_gc_overhead_limit(
-                                          size_t young_live,
-                                          size_t eden_live,
+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,
-                                          bool   is_full_gc,
-                                          GCCause::Cause gc_cause,
-                                          SoftRefPolicy* soft_ref_policy) {
+                                        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) {}
 
-  // 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
+  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 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.
+    // 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 the
-  // young gen or the average of the live in the young gen.
+    // 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()->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());
+      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 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());
+    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)(
-        "PSAdaptiveSizePolicy::check_gc_overhead_limit:"
+          "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);
-
-  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();
-    }
-  }
+          promo_limit, _max_eden_size, total_free_limit,
+          _max_old_gen_size, _max_eden_size,
+          (size_t)mem_free_limit);
 
-  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());
-    }
+    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 eden_live,
+                                          size_t max_old_gen_size,
+                                          size_t max_eden_size,
+                                          bool   is_full_gc,
+                                          GCCause::Cause gc_cause,
+                                          SoftRefPolicy* soft_ref_policy) {
+
+  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
 
 bool AdaptiveSizePolicy::print() const {
   assert(UseAdaptiveSizePolicy, "UseAdaptiveSizePolicy need to be enabled.");
< prev index next >