1 /*
  2  * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "gc/shenandoah/shenandoahMetrics.hpp"
 27 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 28 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
 29 #include "gc/shenandoah/shenandoahFreeSet.hpp"
 30 
 31 ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot() {
 32   _heap = ShenandoahHeap::heap();
 33 }
 34 
 35 void ShenandoahMetricsSnapshot::snap_before() {
 36   _used_before = _heap->used();
 37   _if_before = _heap->free_set()->internal_fragmentation();
 38   _ef_before = _heap->free_set()->external_fragmentation();
 39 }
 40 void ShenandoahMetricsSnapshot::snap_after() {
 41   _used_after = _heap->used();
 42   _if_after = _heap->free_set()->internal_fragmentation();
 43   _ef_after = _heap->free_set()->external_fragmentation();
 44 }
 45 
 46 // For degenerated GC, generation is Young in generational mode, Global in non-generational mode.
 47 // For full GC, generation is always Global.
 48 //
 49 // Note that the size of the chosen collection set is proportional to the relevant generation's collection set.
 50 // Note also that the generation size may change following selection of the collection set, as a side effect
 51 // of evacuation.  Evacuation may promote objects, causing old to grow and young to shrink.  Or this may be a
 52 // mixed evacuation.  When old regions are evacuated, this typically allows young to expand.  In all of these
 53 // various scenarios, the purpose of asking is_good_progress() is to determine if there is enough memory available
 54 // within young generation to justify making an attempt to perform a concurrent collection.  For this reason, we'll
 55 // use the current size of the generation (which may not be different than when the collection set was chosen) to
 56 // assess how much free memory we require in order to consider the most recent GC to have had good progress.
 57 
 58 bool ShenandoahMetricsSnapshot::is_good_progress(ShenandoahGeneration* generation) {
 59   // Under the critical threshold?
 60   ShenandoahFreeSet* free_set = _heap->free_set();
 61   size_t free_actual   = free_set->available();
 62 
 63   // ShenandoahCriticalFreeThreshold is expressed as a percentage.  We multiple this percentage by 1/100th
 64   // of the generation capacity to determine whether the available memory within the generation exceeds the
 65   // critical threshold.
 66   size_t free_expected = (generation->max_capacity() / 100) * ShenandoahCriticalFreeThreshold;
 67 
 68   bool prog_free = free_actual >= free_expected;
 69   log_info(gc, ergo)("%s progress for free space: " SIZE_FORMAT "%s, need " SIZE_FORMAT "%s",
 70                      prog_free ? "Good" : "Bad",
 71                      byte_size_in_proper_unit(free_actual),   proper_unit_for_byte_size(free_actual),
 72                      byte_size_in_proper_unit(free_expected), proper_unit_for_byte_size(free_expected));
 73   if (!prog_free) {
 74     return false;
 75   }
 76 
 77   // Freed up enough?
 78   size_t progress_actual   = (_used_before > _used_after) ? _used_before - _used_after : 0;
 79   size_t progress_expected = ShenandoahHeapRegion::region_size_bytes();
 80   bool prog_used = progress_actual >= progress_expected;
 81   log_info(gc, ergo)("%s progress for used space: " SIZE_FORMAT "%s, need " SIZE_FORMAT "%s",
 82                      prog_used ? "Good" : "Bad",
 83                      byte_size_in_proper_unit(progress_actual),   proper_unit_for_byte_size(progress_actual),
 84                      byte_size_in_proper_unit(progress_expected), proper_unit_for_byte_size(progress_expected));
 85   if (prog_used) {
 86     return true;
 87   }
 88 
 89   // Internal fragmentation is down?
 90   double if_actual = _if_before - _if_after;
 91   double if_expected = 0.01; // 1% should be enough
 92   bool prog_if = if_actual >= if_expected;
 93   log_info(gc, ergo)("%s progress for internal fragmentation: %.1f%%, need %.1f%%",
 94                      prog_if ? "Good" : "Bad",
 95                      if_actual * 100, if_expected * 100);
 96   if (prog_if) {
 97     return true;
 98   }
 99 
100   // External fragmentation is down?
101   double ef_actual = _ef_before - _ef_after;
102   double ef_expected = 0.01; // 1% should be enough
103   bool prog_ef = ef_actual >= ef_expected;
104   log_info(gc, ergo)("%s progress for external fragmentation: %.1f%%, need %.1f%%",
105                      prog_ef ? "Good" : "Bad",
106                      ef_actual * 100, ef_expected * 100);
107   if (prog_ef) {
108     return true;
109   }
110 
111   // Nothing good had happened.
112   return false;
113 }