From 37b5d3093c40c24aaad3662db23f883910eb7bd3 Mon Sep 17 00:00:00 2001 From: Taylan Kammer Date: Fri, 21 Aug 2026 15:14:37 +0200 Subject: Meta alloc improvement. --- src/zisp/gc/meta_alloc.zig | 55 +++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/zisp/gc/meta_alloc.zig b/src/zisp/gc/meta_alloc.zig index e8502df..1fbe1ab 100644 --- a/src/zisp/gc/meta_alloc.zig +++ b/src/zisp/gc/meta_alloc.zig @@ -397,9 +397,9 @@ fn free_into_fl( } /// For every size class: Flushes this thread's free slot cache into the global -/// free-list, and splits remaining reserved memory into slots which are then -/// also pushed into the global free-list. It's crucial for threads to call -/// this function before terminating, or else memory is leaked. +/// free-list, and splits remaining reserved memory into slots which are also +/// pushed onto the global free-list. It's crucial for threads to call this +/// function before terminating, or else memory is leaked. export fn flush_thread_reserves() void { var sci: u8 = 0; var slot_len: UnitIdx = SIZES[0] / @sizeOf(Unit); @@ -411,38 +411,33 @@ export fn flush_thread_reserves() void { const tl = &tl_slab_infos[sci]; const slab: *Slab = &slabs[sci]; const fsc_lim = maxFscCountForSizeClassIndex(sci); + const flush_max = fsc_lim / 2; - const chunk_max = fsc_lim / 2; + // We could first flush the current fsc and then move on to splitting + // reserved memory, but this could result in an "undersized" chunk from + // the current fsc and then a second undersized chunk when we reach the + // end of reserved memory. A simple improvement is to do it this way + // around instead: - // Up to two iterations to flush the entire fsc. - while (tl.fsc_count != 0) { - flush_fsc(info, tl, slab, @min(chunk_max, tl.fsc_count - 1)); - } - - // Now turn slots between wm_lo and wm_hi into free-list entries; most - // easily done by writing them into tl.fsc and reusing the function to - // flush the fsc entries every time chunk_max + 1 is hit. + // Add remaining reserved memory to fsc in a loop, flushing every time + // we hit the fsc limit. while (tl.wm_lo < tl.wm_hi) : (tl.wm_lo += slot_len) { - if (tl.fsc_count > chunk_max) { - flush_fsc(info, tl, slab, chunk_max); + const idx = tl.wm_lo; + const ptr = slab[idx..].ptr; + if (tl.fsc_count == fsc_lim) { + free_into_fl(info, tl, ptr, idx, flush_max); + } else { + tl.fsc[tl.fsc_count] = idx; + tl.fsc_count += 1; } - tl.fsc[tl.fsc_count] = tl.wm_lo; - tl.fsc_count += 1; } - if (tl.fsc_count != 0) { - flush_fsc(info, tl, slab, tl.fsc_count - 1); + + // Now flush the rest, in two iterations if necessary. + while (tl.fsc_count != 0) { + tl.fsc_count -= 1; + const idx = tl.fsc[tl.fsc_count]; + const ptr = slab[idx..].ptr; + free_into_fl(info, tl, ptr, idx, @min(flush_max, tl.fsc_count)); } } } - -fn flush_fsc( - info: *SlabInfo, - tl: *TlSlabInfo, - slab: *Slab, - n_more: UnitIdx, -) void { - tl.fsc_count -= 1; - const idx = tl.fsc[tl.fsc_count]; - const ptr: SlotPtr = slab[idx..].ptr; - free_into_fl(info, tl, ptr, idx, n_more); -} -- cgit v1.2.3