changeset 58522:31bb8878e42e

8241351: Shenandoah: fragmentation metrics overhaul Reviewed-by: rkennke
author shade
date Mon, 23 Mar 2020 19:14:01 +0100
parents fcbd54a2c2d9
children c9fba77b1507
files src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp
diffstat 4 files changed, 107 insertions(+), 102 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp	Mon Mar 23 17:57:13 2020 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp	Mon Mar 23 19:14:01 2020 +0100
@@ -476,6 +476,7 @@
 
       size_t total_used = 0;
       size_t total_free = 0;
+      size_t total_free_ext = 0;
 
       for (size_t idx = _mutator_leftmost; idx <= _mutator_rightmost; idx++) {
         if (is_mutator_free(idx)) {
@@ -484,8 +485,13 @@
 
           max = MAX2(max, free);
 
-          if (r->is_empty() && (last_idx + 1 == idx)) {
-            empty_contig++;
+          if (r->is_empty()) {
+            total_free_ext += free;
+            if (last_idx + 1 == idx) {
+              empty_contig++;
+            } else {
+              empty_contig = 1;
+            }
           } else {
             empty_contig = 0;
           }
@@ -509,8 +515,8 @@
       );
 
       size_t frag_ext;
-      if (free > 0) {
-        frag_ext = 100 - (100 * max_humongous / free);
+      if (total_free_ext > 0) {
+        frag_ext = 100 - (100 * max_humongous / total_free_ext);
       } else {
         frag_ext = 0;
       }
@@ -603,6 +609,96 @@
   }
 }
 
+/*
+ * Internal fragmentation metric: describes how fragmented the heap regions are.
+ *
+ * It is derived as:
+ *
+ *               sum(used[i]^2, i=0..k)
+ *   IF = 1 - ------------------------------
+ *              C * sum(used[i], i=0..k)
+ *
+ * ...where k is the number of regions in computation, C is the region capacity, and
+ * used[i] is the used space in the region.
+ *
+ * The non-linearity causes IF to be lower for the cases where the same total heap
+ * used is densely packed. For example:
+ *   a) Heap is completely full  => IF = 0
+ *   b) Heap is half full, first 50% regions are completely full => IF = 0
+ *   c) Heap is half full, each region is 50% full => IF = 1/2
+ *   d) Heap is quarter full, first 50% regions are completely full => IF = 0
+ *   e) Heap is quarter full, each region is 25% full => IF = 3/4
+ *   f) Heap has one small object per each region => IF =~ 1
+ */
+double ShenandoahFreeSet::internal_fragmentation() {
+  double squared = 0;
+  double linear = 0;
+  int count = 0;
+
+  for (size_t index = _mutator_leftmost; index <= _mutator_rightmost; index++) {
+    if (is_mutator_free(index)) {
+      ShenandoahHeapRegion* r = _heap->get_region(index);
+      size_t used = r->used();
+      squared += used * used;
+      linear += used;
+      count++;
+    }
+  }
+
+  if (count > 0) {
+    double s = squared / (ShenandoahHeapRegion::region_size_bytes() * linear);
+    return 1 - s;
+  } else {
+    return 0;
+  }
+}
+
+/*
+ * External fragmentation metric: describes how fragmented the heap is.
+ *
+ * It is derived as:
+ *
+ *   EF = 1 - largest_contiguous_free / total_free
+ *
+ * For example:
+ *   a) Heap is completely empty => EF = 0
+ *   b) Heap is completely full => EF = 0
+ *   c) Heap is first-half full => EF = 1/2
+ *   d) Heap is half full, full and empty regions interleave => EF =~ 1
+ */
+double ShenandoahFreeSet::external_fragmentation() {
+  size_t last_idx = 0;
+  size_t max_contig = 0;
+  size_t empty_contig = 0;
+
+  size_t free = 0;
+
+  for (size_t index = _mutator_leftmost; index <= _mutator_rightmost; index++) {
+    if (is_mutator_free(index)) {
+      ShenandoahHeapRegion* r = _heap->get_region(index);
+      if (r->is_empty()) {
+        free += ShenandoahHeapRegion::region_size_bytes();
+        if (last_idx + 1 == index) {
+          empty_contig++;
+        } else {
+          empty_contig = 1;
+        }
+      } else {
+        empty_contig = 0;
+      }
+
+      max_contig = MAX2(max_contig, empty_contig);
+      last_idx = index;
+    }
+  }
+
+  if (free > 0) {
+    return 1 - (1.0 * max_contig * ShenandoahHeapRegion::region_size_bytes() / free);
+  } else {
+    return 0;
+  }
+}
+
 #ifdef ASSERT
 void ShenandoahFreeSet::assert_heaplock_owned_by_current_thread() const {
   _heap->assert_heaplock_owned_by_current_thread();
--- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp	Mon Mar 23 17:57:13 2020 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp	Mon Mar 23 19:14:01 2020 +0100
@@ -92,6 +92,9 @@
   HeapWord* allocate(ShenandoahAllocRequest& req, bool& in_new_region);
   size_t unsafe_peek_free() const;
 
+  double internal_fragmentation();
+  double external_fragmentation();
+
   void print_on(outputStream* out) const;
 };
 
--- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp	Mon Mar 23 17:57:13 2020 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp	Mon Mar 23 19:14:01 2020 +0100
@@ -28,104 +28,19 @@
 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
 #include "gc/shenandoah/shenandoahFreeSet.hpp"
 
-/*
- * Internal fragmentation metric: describes how fragmented the heap regions are.
- *
- * It is derived as:
- *
- *               sum(used[i]^2, i=0..k)
- *   IF = 1 - ------------------------------
- *              C * sum(used[i], i=0..k)
- *
- * ...where k is the number of regions in computation, C is the region capacity, and
- * used[i] is the used space in the region.
- *
- * The non-linearity causes IF to be lower for the cases where the same total heap
- * used is densely packed. For example:
- *   a) Heap is completely full  => IF = 0
- *   b) Heap is half full, first 50% regions are completely full => IF = 0
- *   c) Heap is half full, each region is 50% full => IF = 1/2
- *   d) Heap is quarter full, first 50% regions are completely full => IF = 0
- *   e) Heap is quarter full, each region is 25% full => IF = 3/4
- *   f) Heap has the small object per each region => IF =~ 1
- */
-double ShenandoahMetrics::internal_fragmentation() {
-  ShenandoahHeap* heap = ShenandoahHeap::heap();
-
-  double squared = 0;
-  double linear = 0;
-  int count = 0;
-  for (size_t c = 0; c < heap->num_regions(); c++) {
-    ShenandoahHeapRegion* r = heap->get_region(c);
-    size_t used = r->used();
-    squared += used * used;
-    linear += used;
-    count++;
-  }
-
-  if (count > 0) {
-    double s = squared / (ShenandoahHeapRegion::region_size_bytes() * linear);
-    return 1 - s;
-  } else {
-    return 0;
-  }
-}
-
-/*
- * External fragmentation metric: describes how fragmented the heap is.
- *
- * It is derived as:
- *
- *   EF = 1 - largest_contiguous_free / total_free
- *
- * For example:
- *   a) Heap is completely empty => EF = 0
- *   b) Heap is completely full => EF = 1
- *   c) Heap is first-half full => EF = 1/2
- *   d) Heap is half full, full and empty regions interleave => EF =~ 1
- */
-double ShenandoahMetrics::external_fragmentation() {
-  ShenandoahHeap* heap = ShenandoahHeap::heap();
-
-  size_t last_idx = 0;
-  size_t max_contig = 0;
-  size_t empty_contig = 0;
-
-  size_t free = 0;
-  for (size_t c = 0; c < heap->num_regions(); c++) {
-    ShenandoahHeapRegion* r = heap->get_region(c);
-
-    if (r->is_empty() && (last_idx + 1 == c)) {
-      empty_contig++;
-    } else {
-      empty_contig = 0;
-    }
-
-    free += r->free();
-    max_contig = MAX2(max_contig, empty_contig);
-    last_idx = c;
-  }
-
-  if (free > 0) {
-    return 1 - (1.0 * max_contig * ShenandoahHeapRegion::region_size_bytes() / free);
-  } else {
-    return 1;
-  }
-}
-
 ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot() {
   _heap = ShenandoahHeap::heap();
 }
 
 void ShenandoahMetricsSnapshot::snap_before() {
   _used_before = _heap->used();
-  _if_before = ShenandoahMetrics::internal_fragmentation();
-  _ef_before = ShenandoahMetrics::external_fragmentation();
+  _if_before = _heap->free_set()->internal_fragmentation();
+  _ef_before = _heap->free_set()->external_fragmentation();
 }
 void ShenandoahMetricsSnapshot::snap_after() {
   _used_after = _heap->used();
-  _if_after = ShenandoahMetrics::internal_fragmentation();
-  _ef_after = ShenandoahMetrics::external_fragmentation();
+  _if_after = _heap->free_set()->internal_fragmentation();
+  _ef_after = _heap->free_set()->external_fragmentation();
 }
 
 bool ShenandoahMetricsSnapshot::is_good_progress() {
--- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp	Mon Mar 23 17:57:13 2020 +0000
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp	Mon Mar 23 19:14:01 2020 +0100
@@ -27,15 +27,6 @@
 
 #include "gc/shenandoah/shenandoahHeap.hpp"
 
-class ShenandoahMetrics {
-private:
-  ShenandoahMetrics() {}
-
-public:
-  static double internal_fragmentation();
-  static double external_fragmentation();
-};
-
 class ShenandoahMetricsSnapshot : public StackObj {
 private:
   ShenandoahHeap* _heap;