Skip to content
Permalink
Browse files

8241351: Shenandoah: fragmentation metrics overhaul

Reviewed-by: rkennke
  • Loading branch information
shipilev committed Mar 23, 2020
1 parent edb6783 commit f37149b1c510020cc7a62b21905d1744eb82f37f
@@ -476,6 +476,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)) {
@@ -484,8 +485,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;
}
@@ -509,8 +515,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;
}
@@ -603,6 +609,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();
@@ -92,6 +92,9 @@ class ShenandoahFreeSet : public CHeapObj<mtGC> {
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;
};

@@ -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() {
@@ -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;

0 comments on commit f37149b

Please sign in to comment.