< prev index next >

src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp

Print this page
@@ -25,11 +25,11 @@
  #include "precompiled.hpp"
  
  #include "gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.hpp"
  #include "gc/shenandoah/shenandoahCollectionSet.hpp"
  #include "gc/shenandoah/shenandoahFreeSet.hpp"
- #include "gc/shenandoah/shenandoahHeap.inline.hpp"
+ #include "gc/shenandoah/shenandoahGeneration.hpp"
  #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
  #include "logging/log.hpp"
  #include "logging/logTag.hpp"
  #include "utilities/quickSort.hpp"
  

@@ -52,12 +52,12 @@
  // that the true value of our estimate is outside the interval. These are used
  // as bounds on the adjustments applied at the outcome of a GC cycle.
  const double ShenandoahAdaptiveHeuristics::MINIMUM_CONFIDENCE = 0.319; // 25%
  const double ShenandoahAdaptiveHeuristics::MAXIMUM_CONFIDENCE = 3.291; // 99.9%
  
- ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics() :
-   ShenandoahHeuristics(),
+ ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics(ShenandoahGeneration* generation) :
+   ShenandoahHeuristics(generation),
    _margin_of_error_sd(ShenandoahAdaptiveInitialConfidence),
    _spike_threshold_sd(ShenandoahAdaptiveInitialSpikeThreshold),
    _last_trigger(OTHER) { }
  
  ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() {}

@@ -82,11 +82,11 @@
    // Therefore, we start by sorting the regions by garbage. Then we unconditionally add the best candidates
    // before we meet min_garbage. Then we add all candidates that fit with a garbage threshold before
    // we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme,
    // ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit.
  
-   size_t capacity    = ShenandoahHeap::heap()->soft_max_capacity();
+   size_t capacity    = _generation->soft_max_capacity();
    size_t max_cset    = (size_t)((1.0 * capacity / 100 * ShenandoahEvacReserve) / ShenandoahEvacWaste);
    size_t free_target = (capacity / 100 * ShenandoahMinFreeThreshold) + max_cset;
    size_t min_garbage = (free_target > actual_free ? (free_target - actual_free) : 0);
  
    log_info(gc, ergo)("Adaptive CSet Selection. Target Free: " SIZE_FORMAT "%s, Actual Free: "

@@ -194,38 +194,47 @@
  static double saturate(double value, double min, double max) {
    return MAX2(MIN2(value, max), min);
  }
  
  bool ShenandoahAdaptiveHeuristics::should_start_gc() {
-   ShenandoahHeap* heap = ShenandoahHeap::heap();
-   size_t max_capacity = heap->max_capacity();
-   size_t capacity = heap->soft_max_capacity();
-   size_t available = heap->free_set()->available();
-   size_t allocated = heap->bytes_allocated_since_gc_start();
+   size_t max_capacity = _generation->max_capacity();
+   size_t capacity = _generation->soft_max_capacity();
+   size_t available = _generation->available();
+   size_t allocated = _generation->bytes_allocated_since_gc_start();
+ 
+   log_debug(gc)("should_start_gc (%s)? available: " SIZE_FORMAT ", soft_max_capacity: " SIZE_FORMAT
+                 ", max_capacity: " SIZE_FORMAT ", allocated: " SIZE_FORMAT,
+                 _generation->name(), available, capacity, max_capacity, allocated);
  
    // Make sure the code below treats available without the soft tail.
    size_t soft_tail = max_capacity - capacity;
    available = (available > soft_tail) ? (available - soft_tail) : 0;
  
    // Track allocation rate even if we decide to start a cycle for other reasons.
    double rate = _allocation_rate.sample(allocated);
    _last_trigger = OTHER;
  
    size_t min_threshold = capacity / 100 * ShenandoahMinFreeThreshold;
+ 
+   log_debug(gc)("  available adjusted to: " SIZE_FORMAT ", min_threshold: " SIZE_FORMAT ", ShenandoahMinFreeThreshold: " SIZE_FORMAT,
+                 available, min_threshold, ShenandoahMinFreeThreshold);
+ 
    if (available < min_threshold) {
-     log_info(gc)("Trigger: Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)",
+     log_info(gc)("Trigger (%s): Free (" SIZE_FORMAT "%s) is below minimum threshold (" SIZE_FORMAT "%s)",
+                  _generation->name(),
                   byte_size_in_proper_unit(available),     proper_unit_for_byte_size(available),
                   byte_size_in_proper_unit(min_threshold), proper_unit_for_byte_size(min_threshold));
      return true;
    }
  
+   // Check if we need to learn a bit about the application
    const size_t max_learn = ShenandoahLearningSteps;
    if (_gc_times_learned < max_learn) {
      size_t init_threshold = capacity / 100 * ShenandoahInitFreeThreshold;
      if (available < init_threshold) {
-       log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "%s) is below initial threshold (" SIZE_FORMAT "%s)",
-                    _gc_times_learned + 1, max_learn,
+       log_info(gc)("Trigger (%s): Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "%s) is below initial threshold (" SIZE_FORMAT "%s)",
+                    _generation->name(), _gc_times_learned + 1, max_learn,
                     byte_size_in_proper_unit(available),      proper_unit_for_byte_size(available),
                     byte_size_in_proper_unit(init_threshold), proper_unit_for_byte_size(init_threshold));
        return true;
      }
    }

@@ -241,13 +250,16 @@
    allocation_headroom -= MIN2(allocation_headroom, spike_headroom);
    allocation_headroom -= MIN2(allocation_headroom, penalties);
  
    double avg_cycle_time = _gc_time_history->davg() + (_margin_of_error_sd * _gc_time_history->dsd());
    double avg_alloc_rate = _allocation_rate.upper_bound(_margin_of_error_sd);
+   log_debug(gc)("%s: average GC time: %.2f ms, allocation rate: %.0f %s/s",
+     _generation->name(), avg_cycle_time * 1000, byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate));
+ 
    if (avg_cycle_time > allocation_headroom / avg_alloc_rate) {
-     log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s) (margin of error = %.2f)",
-                  avg_cycle_time * 1000,
+     log_info(gc)("Trigger (%s): Average GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s) (margin of error = %.2f)",
+                  _generation->name(), avg_cycle_time * 1000,
                   byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate),
                   byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom),
                   _margin_of_error_sd);
  
      log_info(gc, ergo)("Free headroom: " SIZE_FORMAT "%s (free) - " SIZE_FORMAT "%s (spike) - " SIZE_FORMAT "%s (penalties) = " SIZE_FORMAT "%s",

@@ -260,12 +272,12 @@
      return true;
    }
  
    bool is_spiking = _allocation_rate.is_spiking(rate, _spike_threshold_sd);
    if (is_spiking && avg_cycle_time > allocation_headroom / rate) {
-     log_info(gc)("Trigger: Average GC time (%.2f ms) is above the time for instantaneous allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s) (spike threshold = %.2f)",
-                  avg_cycle_time * 1000,
+     log_info(gc)("Trigger (%s): Average GC time (%.2f ms) is above the time for instantaneous allocation rate (%.0f %sB/s) to deplete free headroom (" SIZE_FORMAT "%s) (spike threshold = %.2f)",
+                  _generation->name(), avg_cycle_time * 1000,
                   byte_size_in_proper_unit(rate), proper_unit_for_byte_size(rate),
                   byte_size_in_proper_unit(allocation_headroom), proper_unit_for_byte_size(allocation_headroom),
                   _spike_threshold_sd);
      _last_trigger = SPIKE;
      return true;
< prev index next >