summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTaylan Kammer <taylan.kammer@gmail.com>2026-08-21 15:14:37 +0200
committerTaylan Kammer <taylan.kammer@gmail.com>2026-08-21 15:14:37 +0200
commit37b5d3093c40c24aaad3662db23f883910eb7bd3 (patch)
tree3464fffe79fd4811dca0b8a30b8988c20b061758 /src
parentb233a858b800a96ac71d357570b4e72dc5519d34 (diff)
Meta alloc improvement.
Diffstat (limited to 'src')
-rw-r--r--src/zisp/gc/meta_alloc.zig55
1 files 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);
-}