diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 13e9877885..4eb9619775 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -472,6 +472,7 @@ void ShenandoahFreeSet::log_status() { 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)) { @@ -480,8 +481,13 @@ void ShenandoahFreeSet::log_status() { 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; } @@ -505,8 +511,8 @@ void ShenandoahFreeSet::log_status() { ); 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; } @@ -599,6 +605,96 @@ void ShenandoahFreeSet::print_on(outputStream* out) const { } } +/* + * 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(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index be3358c236..d3a9278afb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -91,6 +91,9 @@ public: 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; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp index 413e12807d..5b4c2ae5bc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.cpp @@ -27,104 +27,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() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp index 853725fefb..a63c16513c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMetrics.hpp @@ -26,15 +26,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;