< prev index next >

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

Print this page
*** 1,7 ***
--- 1,8 ---
  /*
   * Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved.
+  * Copyright Amazon.com Inc. 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.

*** 22,36 ***
   *
   */
  
  #include "precompiled.hpp"
  #include "gc/shared/gcCause.hpp"
- #include "gc/shenandoah/shenandoahCollectionSet.inline.hpp"
  #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
- #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
  #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
  #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
  #include "logging/log.hpp"
  #include "logging/logTag.hpp"
  #include "runtime/globals_extension.hpp"
  
  int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) {
!   if (a._garbage > b._garbage)
      return -1;
!   else if (a._garbage < b._garbage)
      return 1;
    else return 0;
  }
  
  ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) :
    _space_info(space_info),
    _region_data(nullptr),
    _cycle_start(os::elapsedTime()),
    _last_cycle_end(0),
    _gc_times_learned(0),
    _gc_time_penalties(0),
!   _gc_time_history(new TruncatedSeq(10, ShenandoahAdaptiveDecayFactor)),
    _metaspace_oom()
  {
    size_t num_regions = ShenandoahHeap::heap()->num_regions();
    assert(num_regions > 0, "Sanity");
  
--- 23,37 ---
   *
   */
  
  #include "precompiled.hpp"
  #include "gc/shared/gcCause.hpp"
  #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
  #include "gc/shenandoah/shenandoahHeapRegion.inline.hpp"
  #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
  #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
  #include "logging/log.hpp"
  #include "logging/logTag.hpp"
  #include "runtime/globals_extension.hpp"
+ #include "utilities/quickSort.hpp"
  
+ // sort by decreasing garbage (so most garbage comes first)
  int ShenandoahHeuristics::compare_by_garbage(RegionData a, RegionData b) {
!   if (a._u._garbage > b._u._garbage)
      return -1;
!   else if (a._u._garbage < b._u._garbage)
      return 1;
    else return 0;
  }
  
  ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) :
    _space_info(space_info),
    _region_data(nullptr),
+   _guaranteed_gc_interval(0),
    _cycle_start(os::elapsedTime()),
    _last_cycle_end(0),
    _gc_times_learned(0),
    _gc_time_penalties(0),
!   _gc_cycle_time_history(new TruncatedSeq(Moving_Average_Samples, ShenandoahAdaptiveDecayFactor)),
    _metaspace_oom()
  {
    size_t num_regions = ShenandoahHeap::heap()->num_regions();
    assert(num_regions > 0, "Sanity");
  

*** 61,11 ***
  ShenandoahHeuristics::~ShenandoahHeuristics() {
    FREE_C_HEAP_ARRAY(RegionGarbage, _region_data);
  }
  
  void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) {
!   assert(collection_set->count() == 0, "Must be empty");
  
    ShenandoahHeap* heap = ShenandoahHeap::heap();
  
    // Check all pinned regions have updated status before choosing the collection set.
    heap->assert_pinned_region_status();
--- 63,11 ---
  ShenandoahHeuristics::~ShenandoahHeuristics() {
    FREE_C_HEAP_ARRAY(RegionGarbage, _region_data);
  }
  
  void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) {
!   assert(collection_set->is_empty(), "Must be empty");
  
    ShenandoahHeap* heap = ShenandoahHeap::heap();
  
    // Check all pinned regions have updated status before choosing the collection set.
    heap->assert_pinned_region_status();

*** 104,11 ***
          immediate_garbage += garbage;
          region->make_trash_immediate();
        } else {
          // This is our candidate for later consideration.
          candidates[cand_idx]._region = region;
!         candidates[cand_idx]._garbage = garbage;
          cand_idx++;
        }
      } else if (region->is_humongous_start()) {
        // Reclaim humongous regions here, and count them as the immediate garbage
  #ifdef ASSERT
--- 106,11 ---
          immediate_garbage += garbage;
          region->make_trash_immediate();
        } else {
          // This is our candidate for later consideration.
          candidates[cand_idx]._region = region;
!         candidates[cand_idx]._u._garbage = garbage;
          cand_idx++;
        }
      } else if (region->is_humongous_start()) {
        // Reclaim humongous regions here, and count them as the immediate garbage
  #ifdef ASSERT

*** 145,29 ***
    if (immediate_percent <= ShenandoahImmediateThreshold) {
      choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free);
    }
  
    size_t cset_percent = (total_garbage == 0) ? 0 : (collection_set->garbage() * 100 / total_garbage);
- 
    size_t collectable_garbage = collection_set->garbage() + immediate_garbage;
    size_t collectable_garbage_percent = (total_garbage == 0) ? 0 : (collectable_garbage * 100 / total_garbage);
  
    log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
!                      "Immediate: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
!                      "CSet: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%)",
  
                       byte_size_in_proper_unit(collectable_garbage),
                       proper_unit_for_byte_size(collectable_garbage),
                       collectable_garbage_percent,
  
                       byte_size_in_proper_unit(immediate_garbage),
                       proper_unit_for_byte_size(immediate_garbage),
                       immediate_percent,
  
                       byte_size_in_proper_unit(collection_set->garbage()),
                       proper_unit_for_byte_size(collection_set->garbage()),
!                      cset_percent);
  }
  
  void ShenandoahHeuristics::record_cycle_start() {
    _cycle_start = os::elapsedTime();
  }
--- 147,30 ---
    if (immediate_percent <= ShenandoahImmediateThreshold) {
      choose_collection_set_from_regiondata(collection_set, candidates, cand_idx, immediate_garbage + free);
    }
  
    size_t cset_percent = (total_garbage == 0) ? 0 : (collection_set->garbage() * 100 / total_garbage);
    size_t collectable_garbage = collection_set->garbage() + immediate_garbage;
    size_t collectable_garbage_percent = (total_garbage == 0) ? 0 : (collectable_garbage * 100 / total_garbage);
  
    log_info(gc, ergo)("Collectable Garbage: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), "
!                      "Immediate: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), " SIZE_FORMAT " regions, "
!                      "CSet: " SIZE_FORMAT "%s (" SIZE_FORMAT "%%), " SIZE_FORMAT " regions",
  
                       byte_size_in_proper_unit(collectable_garbage),
                       proper_unit_for_byte_size(collectable_garbage),
                       collectable_garbage_percent,
  
                       byte_size_in_proper_unit(immediate_garbage),
                       proper_unit_for_byte_size(immediate_garbage),
                       immediate_percent,
+                      immediate_regions,
  
                       byte_size_in_proper_unit(collection_set->garbage()),
                       proper_unit_for_byte_size(collection_set->garbage()),
!                      cset_percent,
+                      collection_set->count());
  }
  
  void ShenandoahHeuristics::record_cycle_start() {
    _cycle_start = os::elapsedTime();
  }

*** 182,15 ***
      // Some of vmTestbase/metaspace tests depend on following line to count GC cycles
      log_info(gc)("Trigger: %s", GCCause::to_string(GCCause::_metadata_GC_threshold));
      return true;
    }
  
!   if (ShenandoahGuaranteedGCInterval > 0) {
      double last_time_ms = (os::elapsedTime() - _last_cycle_end) * 1000;
!     if (last_time_ms > ShenandoahGuaranteedGCInterval) {
!       log_info(gc)("Trigger: Time since last GC (%.0f ms) is larger than guaranteed interval (" UINTX_FORMAT " ms)",
!                    last_time_ms, ShenandoahGuaranteedGCInterval);
        return true;
      }
    }
  
    return false;
--- 185,15 ---
      // Some of vmTestbase/metaspace tests depend on following line to count GC cycles
      log_info(gc)("Trigger: %s", GCCause::to_string(GCCause::_metadata_GC_threshold));
      return true;
    }
  
!   if (_guaranteed_gc_interval > 0) {
      double last_time_ms = (os::elapsedTime() - _last_cycle_end) * 1000;
!     if (last_time_ms > _guaranteed_gc_interval) {
!       log_info(gc)("Trigger (%s): Time since last GC (%.0f ms) is larger than guaranteed interval (" UINTX_FORMAT " ms)",
!                    _space_info->name(), last_time_ms, _guaranteed_gc_interval);
        return true;
      }
    }
  
    return false;

*** 200,11 ***
    return ShenandoahHeap::heap()->shenandoah_policy()->consecutive_degenerated_gc_count() <= ShenandoahFullGCThreshold;
  }
  
  void ShenandoahHeuristics::adjust_penalty(intx step) {
    assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
!           "In range before adjustment: " INTX_FORMAT, _gc_time_penalties);
  
    intx new_val = _gc_time_penalties + step;
    if (new_val < 0) {
      new_val = 0;
    }
--- 203,11 ---
    return ShenandoahHeap::heap()->shenandoah_policy()->consecutive_degenerated_gc_count() <= ShenandoahFullGCThreshold;
  }
  
  void ShenandoahHeuristics::adjust_penalty(intx step) {
    assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
!          "In range before adjustment: " INTX_FORMAT, _gc_time_penalties);
  
    intx new_val = _gc_time_penalties + step;
    if (new_val < 0) {
      new_val = 0;
    }

*** 212,18 ***
      new_val = 100;
    }
    _gc_time_penalties = new_val;
  
    assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
!           "In range after adjustment: " INTX_FORMAT, _gc_time_penalties);
  }
  
! void ShenandoahHeuristics::record_success_concurrent() {
-   _gc_time_history->add(time_since_last_gc());
    _gc_times_learned++;
  
    adjust_penalty(Concurrent_Adjust);
  }
  
  void ShenandoahHeuristics::record_success_degenerated() {
    adjust_penalty(Degenerated_Penalty);
  }
--- 215,21 ---
      new_val = 100;
    }
    _gc_time_penalties = new_val;
  
    assert(0 <= _gc_time_penalties && _gc_time_penalties <= 100,
!          "In range after adjustment: " INTX_FORMAT, _gc_time_penalties);
  }
  
! void ShenandoahHeuristics::record_success_concurrent(bool abbreviated) {
    _gc_times_learned++;
  
    adjust_penalty(Concurrent_Adjust);
+ 
+   if (_gc_times_learned <= ShenandoahLearningSteps || !(abbreviated && ShenandoahAdaptiveIgnoreShortCycles)) {
+     _gc_cycle_time_history->add(elapsed_cycle_time());
+   }
  }
  
  void ShenandoahHeuristics::record_success_degenerated() {
    adjust_penalty(Degenerated_Penalty);
  }

*** 254,8 ***
  
  void ShenandoahHeuristics::initialize() {
    // Nothing to do by default.
  }
  
! double ShenandoahHeuristics::time_since_last_gc() const {
    return os::elapsedTime() - _cycle_start;
  }
--- 260,8 ---
  
  void ShenandoahHeuristics::initialize() {
    // Nothing to do by default.
  }
  
! double ShenandoahHeuristics::elapsed_cycle_time() const {
    return os::elapsedTime() - _cycle_start;
  }
< prev index next >