From 1d157a133df4d802a6070b27199e5b7164df64d6 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Thu, 22 May 2025 14:57:34 +0200 Subject: [PATCH] mmc: Add "headroom" for growable heaps that cannot defragment --- src/mmc.c | 26 +++++++++++++++----------- src/nofl-space.h | 12 ++++++++++-- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/mmc.c b/src/mmc.c index 4bbfed019..a65219a50 100644 --- a/src/mmc.c +++ b/src/mmc.c @@ -575,20 +575,24 @@ compute_progress(struct gc_heap *heap, uintptr_t allocation_since_last_gc) { } static void -grow_heap_for_large_allocation_if_necessary(struct gc_heap *heap, - enum gc_collection_kind gc_kind, - int progress) +grow_heap_if_necessary(struct gc_heap *heap, + enum gc_collection_kind gc_kind, + int progress) { - if (progress || heap->sizer.policy == GC_HEAP_SIZE_FIXED) + if (heap->sizer.policy == GC_HEAP_SIZE_FIXED) return; struct nofl_space *nofl = heap_nofl_space(heap); - if (nofl_space_shrink (nofl, 0)) - return; + size_t pending = nofl_space_shrink(nofl, 0); - ssize_t pending = nofl_space_request_release_memory(nofl, 0); - GC_ASSERT (pending > 0); - resize_heap(heap, heap->size + pending); + size_t needed_headroom = + GC_CONSERVATIVE_TRACE + ? nofl_active_block_count (nofl) * NOFL_BLOCK_SIZE / 16 + : 0; + size_t headroom = nofl_empty_block_count(nofl) * NOFL_BLOCK_SIZE; + + if (headroom < needed_headroom + pending) + resize_heap(heap, heap->size - headroom + needed_headroom + pending); } static int @@ -893,7 +897,7 @@ collect(struct gc_mutator *mut, enum gc_collection_kind requested_kind) { DEBUG("--- total live bytes estimate: %zu\n", live_bytes_estimate); gc_heap_sizer_on_gc(heap->sizer, heap->size, live_bytes_estimate, pause_ns, resize_heap); - grow_heap_for_large_allocation_if_necessary(heap, gc_kind, progress); + grow_heap_if_necessary(heap, gc_kind, progress); heap->size_at_last_gc = heap->size; HEAP_EVENT(heap, restarting_mutators); allow_mutators_to_continue(heap); @@ -992,7 +996,7 @@ allocate_large(struct gc_mutator *mut, size_t size, nofl_space_request_release_memory(nofl_space, npages << lospace->page_size_log2); - while (!nofl_space_shrink(nofl_space, 0)) { + while (nofl_space_shrink(nofl_space, 0)) { if (!trigger_collection(mut, GC_COLLECTION_COMPACTING)) return heap->allocation_failure(heap, size); } diff --git a/src/nofl-space.h b/src/nofl-space.h index e9d9efb3c..b36694d82 100644 --- a/src/nofl-space.h +++ b/src/nofl-space.h @@ -520,6 +520,14 @@ nofl_pop_unavailable_block(struct nofl_space *space, return nofl_block_null(); } +static size_t +nofl_empty_block_count(struct nofl_space *space) { + struct gc_lock lock = nofl_space_lock(space); + size_t ret = nofl_block_count(&space->empty.list); + gc_lock_release(&lock); + return ret; +} + static void nofl_push_empty_block(struct nofl_space *space, struct nofl_block_ref block, @@ -1807,7 +1815,7 @@ nofl_space_add_slabs(struct nofl_space *space, struct nofl_slab *slabs, space->slabs[space->nslabs++] = slabs++; } -static int +static size_t nofl_space_shrink(struct nofl_space *space, size_t bytes) { ssize_t pending = nofl_space_request_release_memory(space, bytes); struct gc_lock lock = nofl_space_lock(space); @@ -1847,7 +1855,7 @@ nofl_space_shrink(struct nofl_space *space, size_t bytes) { // It still may be the case we need to page out more blocks. Only evacuation // can help us then! - return pending <= 0; + return pending <= 0 ? 0 : pending; } static void