1 /* 2 * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 #include "precompiled.hpp" 25 #include "gc/shenandoah/shenandoahMetrics.hpp" 26 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 27 #include "gc/shenandoah/shenandoahHeapRegion.hpp" 28 #include "gc/shenandoah/shenandoahFreeSet.hpp" 29 30 /* 31 * Internal fragmentation metric: describes how fragmented the heap regions are. 32 * 33 * It is derived as: 34 * 35 * sum(used[i]^2, i=0..k) 36 * IF = 1 - ------------------------------ 37 * C * sum(used[i], i=0..k) 38 * 39 * ...where k is the number of regions in computation, C is the region capacity, and 40 * used[i] is the used space in the region. 41 * 42 * The non-linearity causes IF to be lower for the cases where the same total heap 43 * used is densely packed. For example: 44 * a) Heap is completely full => IF = 0 45 * b) Heap is half full, first 50% regions are completely full => IF = 0 46 * c) Heap is half full, each region is 50% full => IF = 1/2 47 * d) Heap is quarter full, first 50% regions are completely full => IF = 0 48 * e) Heap is quarter full, each region is 25% full => IF = 3/4 49 * f) Heap has the small object per each region => IF =~ 1 50 */ 51 double ShenandoahMetrics::internal_fragmentation() { 52 ShenandoahHeap* heap = ShenandoahHeap::heap(); 53 54 double squared = 0; 55 double linear = 0; 56 int count = 0; 57 for (size_t c = 0; c < heap->num_regions(); c++) { 58 ShenandoahHeapRegion* r = heap->get_region(c); 59 size_t used = r->used(); 60 squared += used * used; 61 linear += used; 62 count++; 63 } 64 65 if (count > 0) { 66 double s = squared / (ShenandoahHeapRegion::region_size_bytes() * linear); 67 return 1 - s; 68 } else { 69 return 0; 70 } 71 } 72 73 /* 74 * External fragmentation metric: describes how fragmented the heap is. 75 * 76 * It is derived as: 77 * 78 * EF = 1 - largest_contiguous_free / total_free 79 * 80 * For example: 81 * a) Heap is completely empty => EF = 0 82 * b) Heap is completely full => EF = 1 83 * c) Heap is first-half full => EF = 1/2 84 * d) Heap is half full, full and empty regions interleave => EF =~ 1 85 */ 86 double ShenandoahMetrics::external_fragmentation() { 87 ShenandoahHeap* heap = ShenandoahHeap::heap(); 88 89 size_t last_idx = 0; 90 size_t max_contig = 0; 91 size_t empty_contig = 0; 92 93 size_t free = 0; 94 for (size_t c = 0; c < heap->num_regions(); c++) { 95 ShenandoahHeapRegion* r = heap->get_region(c); 96 97 if (r->is_empty() && (last_idx + 1 == c)) { 98 empty_contig++; 99 } else { 100 empty_contig = 0; 101 } 102 103 free += r->free(); 104 max_contig = MAX2(max_contig, empty_contig); 105 last_idx = c; 106 } 107 108 if (free > 0) { 109 return 1 - (1.0 * max_contig * ShenandoahHeapRegion::region_size_bytes() / free); 110 } else { 111 return 1; 112 } 113 } 114 115 ShenandoahMetricsSnapshot::ShenandoahMetricsSnapshot() { 116 _heap = ShenandoahHeap::heap(); 117 } 118 119 void ShenandoahMetricsSnapshot::snap_before() { 120 _used_before = _heap->used(); 121 _if_before = ShenandoahMetrics::internal_fragmentation(); 122 _ef_before = ShenandoahMetrics::external_fragmentation(); 123 } 124 void ShenandoahMetricsSnapshot::snap_after() { 125 _used_after = _heap->used(); 126 _if_after = ShenandoahMetrics::internal_fragmentation(); 127 _ef_after = ShenandoahMetrics::external_fragmentation(); 128 } 129 130 bool ShenandoahMetricsSnapshot::is_good_progress() { 131 // Under the critical threshold? 132 size_t free_actual = _heap->free_set()->available(); 133 size_t free_expected = _heap->max_capacity() / 100 * ShenandoahCriticalFreeThreshold; 134 bool prog_free = free_actual >= free_expected; 135 log_info(gc, ergo)("%s progress for free space: " SIZE_FORMAT "%s, need " SIZE_FORMAT "%s", 136 prog_free ? "Good" : "Bad", 137 byte_size_in_proper_unit(free_actual), proper_unit_for_byte_size(free_actual), 138 byte_size_in_proper_unit(free_expected), proper_unit_for_byte_size(free_expected)); 139 if (!prog_free) { 140 return false; 141 } 142 143 // Freed up enough? 144 size_t progress_actual = (_used_before > _used_after) ? _used_before - _used_after : 0; 145 size_t progress_expected = ShenandoahHeapRegion::region_size_bytes(); 146 bool prog_used = progress_actual >= progress_expected; 147 log_info(gc, ergo)("%s progress for used space: " SIZE_FORMAT "%s, need " SIZE_FORMAT "%s", 148 prog_used ? "Good" : "Bad", 149 byte_size_in_proper_unit(progress_actual), proper_unit_for_byte_size(progress_actual), 150 byte_size_in_proper_unit(progress_expected), proper_unit_for_byte_size(progress_expected)); 151 if (prog_used) { 152 return true; 153 } 154 155 // Internal fragmentation is down? 156 double if_actual = _if_before - _if_after; 157 double if_expected = 0.01; // 1% should be enough 158 bool prog_if = if_actual >= if_expected; 159 log_info(gc, ergo)("%s progress for internal fragmentation: %.1f%%, need %.1f%%", 160 prog_if ? "Good" : "Bad", 161 if_actual * 100, if_expected * 100); 162 if (prog_if) { 163 return true; 164 } 165 166 // External fragmentation is down? 167 double ef_actual = _ef_before - _ef_after; 168 double ef_expected = 0.01; // 1% should be enough 169 bool prog_ef = ef_actual >= ef_expected; 170 log_info(gc, ergo)("%s progress for external fragmentation: %.1f%%, need %.1f%%", 171 prog_ef ? "Good" : "Bad", 172 ef_actual * 100, ef_expected * 100); 173 if (prog_ef) { 174 return true; 175 } 176 177 // Nothing good had happened. 178 return false; 179 }