Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahFreeSet.cpp
38920 views
/*1* Copyright (c) 2016, 2018, Red Hat, Inc. All rights reserved.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation.6*7* This code is distributed in the hope that it will be useful, but WITHOUT8* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or9* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License10* version 2 for more details (a copy is included in the LICENSE file that11* accompanied this code).12*13* You should have received a copy of the GNU General Public License version14* 2 along with this work; if not, write to the Free Software Foundation,15* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.16*17* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA18* or visit www.oracle.com if you need additional information or have any19* questions.20*21*/2223#include "precompiled.hpp"2425#include "gc_implementation/shenandoah/shenandoahFreeSet.hpp"26#include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"2728ShenandoahFreeSet::ShenandoahFreeSet(ShenandoahHeap* heap,size_t max_regions) :29_heap(heap),30_mutator_free_bitmap(max_regions, /* in_resource_area = */ false),31_collector_free_bitmap(max_regions, /* in_resource_area = */ false),32_max(max_regions)33{34clear_internal();35}3637void ShenandoahFreeSet::increase_used(size_t num_bytes) {38shenandoah_assert_heaplocked();39_used += num_bytes;4041assert(_used <= _capacity, err_msg("must not use more than we have: used: " SIZE_FORMAT42", capacity: " SIZE_FORMAT ", num_bytes: " SIZE_FORMAT,43_used, _capacity, num_bytes));44}4546bool ShenandoahFreeSet::is_mutator_free(size_t idx) const {47assert (idx < _max,48err_msg("index is sane: " SIZE_FORMAT " < " SIZE_FORMAT " (left: " SIZE_FORMAT ", right: " SIZE_FORMAT ")",49idx, _max, _mutator_leftmost, _mutator_rightmost));50return _mutator_free_bitmap.at(idx);51}5253bool ShenandoahFreeSet::is_collector_free(size_t idx) const {54assert (idx < _max,55err_msg("index is sane: " SIZE_FORMAT " < " SIZE_FORMAT " (left: " SIZE_FORMAT ", right: " SIZE_FORMAT ")",56idx, _max, _collector_leftmost, _collector_rightmost));57return _collector_free_bitmap.at(idx);58}5960HeapWord* ShenandoahFreeSet::allocate_single(ShenandoahAllocRequest& req, bool& in_new_region) {61// Scan the bitmap looking for a first fit.62//63// Leftmost and rightmost bounds provide enough caching to walk bitmap efficiently. Normally,64// we would find the region to allocate at right away.65//66// Allocations are biased: new application allocs go to beginning of the heap, and GC allocs67// go to the end. This makes application allocation faster, because we would clear lots68// of regions from the beginning most of the time.69//70// Free set maintains mutator and collector views, and normally they allocate in their views only,71// unless we special cases for stealing and mixed allocations.7273switch (req.type()) {74case ShenandoahAllocRequest::_alloc_tlab:75case ShenandoahAllocRequest::_alloc_shared: {7677// Try to allocate in the mutator view78for (size_t idx = _mutator_leftmost; idx <= _mutator_rightmost; idx++) {79if (is_mutator_free(idx)) {80HeapWord* result = try_allocate_in(_heap->get_region(idx), req, in_new_region);81if (result != NULL) {82return result;83}84}85}8687// There is no recovery. Mutator does not touch collector view at all.88break;89}90case ShenandoahAllocRequest::_alloc_gclab:91case ShenandoahAllocRequest::_alloc_shared_gc: {92// size_t is unsigned, need to dodge underflow when _leftmost = 09394// Fast-path: try to allocate in the collector view first95for (size_t c = _collector_rightmost + 1; c > _collector_leftmost; c--) {96size_t idx = c - 1;97if (is_collector_free(idx)) {98HeapWord* result = try_allocate_in(_heap->get_region(idx), req, in_new_region);99if (result != NULL) {100return result;101}102}103}104105// No dice. Can we borrow space from mutator view?106if (!ShenandoahEvacReserveOverflow) {107return NULL;108}109110// Try to steal the empty region from the mutator view111for (size_t c = _mutator_rightmost + 1; c > _mutator_leftmost; c--) {112size_t idx = c - 1;113if (is_mutator_free(idx)) {114ShenandoahHeapRegion* r = _heap->get_region(idx);115if (is_empty_or_trash(r)) {116flip_to_gc(r);117HeapWord *result = try_allocate_in(r, req, in_new_region);118if (result != NULL) {119return result;120}121}122}123}124125// No dice. Do not try to mix mutator and GC allocations, because126// URWM moves due to GC allocations would expose unparsable mutator127// allocations.128129break;130}131default:132ShouldNotReachHere();133}134135return NULL;136}137138HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, ShenandoahAllocRequest& req, bool& in_new_region) {139assert (!has_no_alloc_capacity(r), err_msg("Performance: should avoid full regions on this path: " SIZE_FORMAT, r->index()));140141try_recycle_trashed(r);142143in_new_region = r->is_empty();144145HeapWord* result = NULL;146size_t size = req.size();147148if (ShenandoahElasticTLAB && req.is_lab_alloc()) {149size_t free = align_size_down(r->free() >> LogHeapWordSize, MinObjAlignment);150if (size > free) {151size = free;152}153if (size >= req.min_size()) {154result = r->allocate(size, req.type());155assert (result != NULL, err_msg("Allocation must succeed: free " SIZE_FORMAT ", actual " SIZE_FORMAT, free, size));156}157} else {158result = r->allocate(size, req.type());159}160161if (result != NULL) {162// Allocation successful, bump stats:163if (req.is_mutator_alloc()) {164increase_used(size * HeapWordSize);165}166167// Record actual allocation size168req.set_actual_size(size);169170if (req.is_gc_alloc()) {171r->set_update_watermark(r->top());172}173}174175if (result == NULL || has_no_alloc_capacity(r)) {176// Region cannot afford this or future allocations. Retire it.177//178// While this seems a bit harsh, especially in the case when this large allocation does not179// fit, but the next small one would, we are risking to inflate scan times when lots of180// almost-full regions precede the fully-empty region where we want allocate the entire TLAB.181// TODO: Record first fully-empty region, and use that for large allocations182183// Record the remainder as allocation waste184if (req.is_mutator_alloc()) {185size_t waste = r->free();186if (waste > 0) {187increase_used(waste);188_heap->notify_mutator_alloc_words(waste >> LogHeapWordSize, true);189}190}191192size_t num = r->index();193_collector_free_bitmap.clear_bit(num);194_mutator_free_bitmap.clear_bit(num);195// Touched the bounds? Need to update:196if (touches_bounds(num)) {197adjust_bounds();198}199assert_bounds();200}201return result;202}203204bool ShenandoahFreeSet::touches_bounds(size_t num) const {205return num == _collector_leftmost || num == _collector_rightmost || num == _mutator_leftmost || num == _mutator_rightmost;206}207208void ShenandoahFreeSet::recompute_bounds() {209// Reset to the most pessimistic case:210_mutator_rightmost = _max - 1;211_mutator_leftmost = 0;212_collector_rightmost = _max - 1;213_collector_leftmost = 0;214215// ...and adjust from there216adjust_bounds();217}218219void ShenandoahFreeSet::adjust_bounds() {220// Rewind both mutator bounds until the next bit.221while (_mutator_leftmost < _max && !is_mutator_free(_mutator_leftmost)) {222_mutator_leftmost++;223}224while (_mutator_rightmost > 0 && !is_mutator_free(_mutator_rightmost)) {225_mutator_rightmost--;226}227// Rewind both collector bounds until the next bit.228while (_collector_leftmost < _max && !is_collector_free(_collector_leftmost)) {229_collector_leftmost++;230}231while (_collector_rightmost > 0 && !is_collector_free(_collector_rightmost)) {232_collector_rightmost--;233}234}235236HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req) {237shenandoah_assert_heaplocked();238239size_t words_size = req.size();240size_t num = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize);241242// No regions left to satisfy allocation, bye.243if (num > mutator_count()) {244return NULL;245}246247// Find the continuous interval of $num regions, starting from $beg and ending in $end,248// inclusive. Contiguous allocations are biased to the beginning.249250size_t beg = _mutator_leftmost;251size_t end = beg;252253while (true) {254if (end >= _max) {255// Hit the end, goodbye256return NULL;257}258259// If regions are not adjacent, then current [beg; end] is useless, and we may fast-forward.260// If region is not completely free, the current [beg; end] is useless, and we may fast-forward.261if (!is_mutator_free(end) || !is_empty_or_trash(_heap->get_region(end))) {262end++;263beg = end;264continue;265}266267if ((end - beg + 1) == num) {268// found the match269break;270}271272end++;273};274275size_t remainder = words_size & ShenandoahHeapRegion::region_size_words_mask();276277// Initialize regions:278for (size_t i = beg; i <= end; i++) {279ShenandoahHeapRegion* r = _heap->get_region(i);280try_recycle_trashed(r);281282assert(i == beg || _heap->get_region(i - 1)->index() + 1 == r->index(), "Should be contiguous");283assert(r->is_empty(), "Should be empty");284285if (i == beg) {286r->make_humongous_start();287} else {288r->make_humongous_cont();289}290291// Trailing region may be non-full, record the remainder there292size_t used_words;293if ((i == end) && (remainder != 0)) {294used_words = remainder;295} else {296used_words = ShenandoahHeapRegion::region_size_words();297}298299r->set_top(r->bottom() + used_words);300301_mutator_free_bitmap.clear_bit(r->index());302}303304// While individual regions report their true use, all humongous regions are305// marked used in the free set.306increase_used(ShenandoahHeapRegion::region_size_bytes() * num);307308if (remainder != 0) {309// Record this remainder as allocation waste310_heap->notify_mutator_alloc_words(ShenandoahHeapRegion::region_size_words() - remainder, true);311}312313// Allocated at left/rightmost? Move the bounds appropriately.314if (beg == _mutator_leftmost || end == _mutator_rightmost) {315adjust_bounds();316}317assert_bounds();318319req.set_actual_size(words_size);320return _heap->get_region(beg)->bottom();321}322323bool ShenandoahFreeSet::is_empty_or_trash(ShenandoahHeapRegion *r) {324return r->is_empty() || r->is_trash();325}326327size_t ShenandoahFreeSet::alloc_capacity(ShenandoahHeapRegion *r) {328if (r->is_trash()) {329// This would be recycled on allocation path330return ShenandoahHeapRegion::region_size_bytes();331} else {332return r->free();333}334}335336bool ShenandoahFreeSet::has_no_alloc_capacity(ShenandoahHeapRegion *r) {337return alloc_capacity(r) == 0;338}339340void ShenandoahFreeSet::try_recycle_trashed(ShenandoahHeapRegion *r) {341if (r->is_trash()) {342_heap->decrease_used(r->used());343r->recycle();344}345}346347void ShenandoahFreeSet::recycle_trash() {348// lock is not reentrable, check we don't have it349shenandoah_assert_not_heaplocked();350351for (size_t i = 0; i < _heap->num_regions(); i++) {352ShenandoahHeapRegion* r = _heap->get_region(i);353if (r->is_trash()) {354ShenandoahHeapLocker locker(_heap->lock());355try_recycle_trashed(r);356}357SpinPause(); // allow allocators to take the lock358}359}360361void ShenandoahFreeSet::flip_to_gc(ShenandoahHeapRegion* r) {362size_t idx = r->index();363364assert(_mutator_free_bitmap.at(idx), "Should be in mutator view");365assert(is_empty_or_trash(r), "Should not be allocated");366367_mutator_free_bitmap.clear_bit(idx);368_collector_free_bitmap.set_bit(idx);369_collector_leftmost = MIN2(idx, _collector_leftmost);370_collector_rightmost = MAX2(idx, _collector_rightmost);371372_capacity -= alloc_capacity(r);373374if (touches_bounds(idx)) {375adjust_bounds();376}377assert_bounds();378}379380void ShenandoahFreeSet::clear() {381shenandoah_assert_heaplocked();382clear_internal();383}384385void ShenandoahFreeSet::clear_internal() {386_mutator_free_bitmap.clear();387_collector_free_bitmap.clear();388_mutator_leftmost = _max;389_mutator_rightmost = 0;390_collector_leftmost = _max;391_collector_rightmost = 0;392_capacity = 0;393_used = 0;394}395396void ShenandoahFreeSet::rebuild() {397shenandoah_assert_heaplocked();398clear();399400for (size_t idx = 0; idx < _heap->num_regions(); idx++) {401ShenandoahHeapRegion* region = _heap->get_region(idx);402if (region->is_alloc_allowed() || region->is_trash()) {403assert(!region->is_cset(), "Shouldn't be adding those to the free set");404405// Do not add regions that would surely fail allocation406if (has_no_alloc_capacity(region)) continue;407408_capacity += alloc_capacity(region);409assert(_used <= _capacity, "must not use more than we have");410411assert(!is_mutator_free(idx), "We are about to add it, it shouldn't be there already");412_mutator_free_bitmap.set_bit(idx);413}414}415416// Evac reserve: reserve trailing space for evacuations417size_t to_reserve = _heap->max_capacity() / 100 * ShenandoahEvacReserve;418size_t reserved = 0;419420for (size_t idx = _heap->num_regions() - 1; idx > 0; idx--) {421if (reserved >= to_reserve) break;422423ShenandoahHeapRegion* region = _heap->get_region(idx);424if (_mutator_free_bitmap.at(idx) && is_empty_or_trash(region)) {425_mutator_free_bitmap.clear_bit(idx);426_collector_free_bitmap.set_bit(idx);427size_t ac = alloc_capacity(region);428_capacity -= ac;429reserved += ac;430}431}432433recompute_bounds();434assert_bounds();435}436437void ShenandoahFreeSet::log_status() {438shenandoah_assert_heaplocked();439440if (ShenandoahLogInfo || PrintGCDetails) {441ResourceMark rm;442outputStream* ls = gclog_or_tty;443444{445size_t last_idx = 0;446size_t max = 0;447size_t max_contig = 0;448size_t empty_contig = 0;449450size_t total_used = 0;451size_t total_free = 0;452size_t total_free_ext = 0;453454for (size_t idx = _mutator_leftmost; idx <= _mutator_rightmost; idx++) {455if (is_mutator_free(idx)) {456ShenandoahHeapRegion *r = _heap->get_region(idx);457size_t free = alloc_capacity(r);458459max = MAX2(max, free);460461if (r->is_empty()) {462total_free_ext += free;463if (last_idx + 1 == idx) {464empty_contig++;465} else {466empty_contig = 1;467}468} else {469empty_contig = 0;470}471472total_used += r->used();473total_free += free;474475max_contig = MAX2(max_contig, empty_contig);476last_idx = idx;477}478}479480size_t max_humongous = max_contig * ShenandoahHeapRegion::region_size_bytes();481482ls->print("Free: " SIZE_FORMAT "%s, Max: " SIZE_FORMAT "%s regular, " SIZE_FORMAT "%s humongous, ",483byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free),484byte_size_in_proper_unit(max), proper_unit_for_byte_size(max),485byte_size_in_proper_unit(max_humongous), proper_unit_for_byte_size(max_humongous)486);487488ls->print("Frag: ");489size_t frag_ext;490if (total_free_ext > 0) {491frag_ext = 100 - (100 * max_humongous / total_free_ext);492} else {493frag_ext = 0;494}495ls->print(SIZE_FORMAT "%% external, ", frag_ext);496497size_t frag_int;498if (mutator_count() > 0) {499frag_int = (100 * (total_used / mutator_count()) / ShenandoahHeapRegion::region_size_bytes());500} else {501frag_int = 0;502}503ls->print(SIZE_FORMAT "%% internal; ", frag_int);504}505506{507size_t max = 0;508size_t total_free = 0;509510for (size_t idx = _collector_leftmost; idx <= _collector_rightmost; idx++) {511if (is_collector_free(idx)) {512ShenandoahHeapRegion *r = _heap->get_region(idx);513size_t free = alloc_capacity(r);514max = MAX2(max, free);515total_free += free;516}517}518519ls->print_cr("Reserve: " SIZE_FORMAT "%s, Max: " SIZE_FORMAT "%s",520byte_size_in_proper_unit(total_free), proper_unit_for_byte_size(total_free),521byte_size_in_proper_unit(max), proper_unit_for_byte_size(max));522}523}524}525526HeapWord* ShenandoahFreeSet::allocate(ShenandoahAllocRequest& req, bool& in_new_region) {527shenandoah_assert_heaplocked();528assert_bounds();529530if (req.size() > ShenandoahHeapRegion::humongous_threshold_words()) {531switch (req.type()) {532case ShenandoahAllocRequest::_alloc_shared:533case ShenandoahAllocRequest::_alloc_shared_gc:534in_new_region = true;535return allocate_contiguous(req);536case ShenandoahAllocRequest::_alloc_gclab:537case ShenandoahAllocRequest::_alloc_tlab:538in_new_region = false;539assert(false, err_msg("Trying to allocate TLAB larger than the humongous threshold: " SIZE_FORMAT " > " SIZE_FORMAT,540req.size(), ShenandoahHeapRegion::humongous_threshold_words()));541return NULL;542default:543ShouldNotReachHere();544return NULL;545}546} else {547return allocate_single(req, in_new_region);548}549}550551size_t ShenandoahFreeSet::unsafe_peek_free() const {552// Deliberately not locked, this method is unsafe when free set is modified.553554for (size_t index = _mutator_leftmost; index <= _mutator_rightmost; index++) {555if (index < _max && is_mutator_free(index)) {556ShenandoahHeapRegion* r = _heap->get_region(index);557if (r->free() >= MinTLABSize) {558return r->free();559}560}561}562563// It appears that no regions left564return 0;565}566567void ShenandoahFreeSet::print_on(outputStream* out) const {568out->print_cr("Mutator Free Set: " SIZE_FORMAT "", mutator_count());569for (size_t index = _mutator_leftmost; index <= _mutator_rightmost; index++) {570if (is_mutator_free(index)) {571_heap->get_region(index)->print_on(out);572}573}574out->print_cr("Collector Free Set: " SIZE_FORMAT "", collector_count());575for (size_t index = _collector_leftmost; index <= _collector_rightmost; index++) {576if (is_collector_free(index)) {577_heap->get_region(index)->print_on(out);578}579}580}581582/*583* Internal fragmentation metric: describes how fragmented the heap regions are.584*585* It is derived as:586*587* sum(used[i]^2, i=0..k)588* IF = 1 - ------------------------------589* C * sum(used[i], i=0..k)590*591* ...where k is the number of regions in computation, C is the region capacity, and592* used[i] is the used space in the region.593*594* The non-linearity causes IF to be lower for the cases where the same total heap595* used is densely packed. For example:596* a) Heap is completely full => IF = 0597* b) Heap is half full, first 50% regions are completely full => IF = 0598* c) Heap is half full, each region is 50% full => IF = 1/2599* d) Heap is quarter full, first 50% regions are completely full => IF = 0600* e) Heap is quarter full, each region is 25% full => IF = 3/4601* f) Heap has one small object per each region => IF =~ 1602*/603double ShenandoahFreeSet::internal_fragmentation() {604double squared = 0;605double linear = 0;606int count = 0;607608for (size_t index = _mutator_leftmost; index <= _mutator_rightmost; index++) {609if (is_mutator_free(index)) {610ShenandoahHeapRegion* r = _heap->get_region(index);611size_t used = r->used();612squared += used * used;613linear += used;614count++;615}616}617618if (count > 0) {619double s = squared / (ShenandoahHeapRegion::region_size_bytes() * linear);620return 1 - s;621} else {622return 0;623}624}625626/*627* External fragmentation metric: describes how fragmented the heap is.628*629* It is derived as:630*631* EF = 1 - largest_contiguous_free / total_free632*633* For example:634* a) Heap is completely empty => EF = 0635* b) Heap is completely full => EF = 0636* c) Heap is first-half full => EF = 1/2637* d) Heap is half full, full and empty regions interleave => EF =~ 1638*/639double ShenandoahFreeSet::external_fragmentation() {640size_t last_idx = 0;641size_t max_contig = 0;642size_t empty_contig = 0;643644size_t free = 0;645646for (size_t index = _mutator_leftmost; index <= _mutator_rightmost; index++) {647if (is_mutator_free(index)) {648ShenandoahHeapRegion* r = _heap->get_region(index);649if (r->is_empty()) {650free += ShenandoahHeapRegion::region_size_bytes();651if (last_idx + 1 == index) {652empty_contig++;653} else {654empty_contig = 1;655}656} else {657empty_contig = 0;658}659660max_contig = MAX2(max_contig, empty_contig);661last_idx = index;662}663}664665if (free > 0) {666return 1 - (1.0 * max_contig * ShenandoahHeapRegion::region_size_bytes() / free);667} else {668return 0;669}670}671672#ifdef ASSERT673void ShenandoahFreeSet::assert_bounds() const {674// Performance invariants. Failing these would not break the free set, but performance675// would suffer.676assert (_mutator_leftmost <= _max, err_msg("leftmost in bounds: " SIZE_FORMAT " < " SIZE_FORMAT, _mutator_leftmost, _max));677assert (_mutator_rightmost < _max, err_msg("rightmost in bounds: " SIZE_FORMAT " < " SIZE_FORMAT, _mutator_rightmost, _max));678679assert (_mutator_leftmost == _max || is_mutator_free(_mutator_leftmost), err_msg("leftmost region should be free: " SIZE_FORMAT, _mutator_leftmost));680assert (_mutator_rightmost == 0 || is_mutator_free(_mutator_rightmost), err_msg("rightmost region should be free: " SIZE_FORMAT, _mutator_rightmost));681682size_t beg_off = _mutator_free_bitmap.get_next_one_offset(0);683size_t end_off = _mutator_free_bitmap.get_next_one_offset(_mutator_rightmost + 1);684assert (beg_off >= _mutator_leftmost, err_msg("free regions before the leftmost: " SIZE_FORMAT ", bound " SIZE_FORMAT, beg_off, _mutator_leftmost));685assert (end_off == _max, err_msg("free regions past the rightmost: " SIZE_FORMAT ", bound " SIZE_FORMAT, end_off, _mutator_rightmost));686687assert (_collector_leftmost <= _max, err_msg("leftmost in bounds: " SIZE_FORMAT " < " SIZE_FORMAT, _collector_leftmost, _max));688assert (_collector_rightmost < _max, err_msg("rightmost in bounds: " SIZE_FORMAT " < " SIZE_FORMAT, _collector_rightmost, _max));689690assert (_collector_leftmost == _max || is_collector_free(_collector_leftmost), err_msg("leftmost region should be free: " SIZE_FORMAT, _collector_leftmost));691assert (_collector_rightmost == 0 || is_collector_free(_collector_rightmost), err_msg("rightmost region should be free: " SIZE_FORMAT, _collector_rightmost));692693beg_off = _collector_free_bitmap.get_next_one_offset(0);694end_off = _collector_free_bitmap.get_next_one_offset(_collector_rightmost + 1);695assert (beg_off >= _collector_leftmost, err_msg("free regions before the leftmost: " SIZE_FORMAT ", bound " SIZE_FORMAT, beg_off, _collector_leftmost));696assert (end_off == _max, err_msg("free regions past the rightmost: " SIZE_FORMAT ", bound " SIZE_FORMAT, end_off, _collector_rightmost));697}698#endif699700701