| ... | @@ -51,10 +51,6 @@ const slab_len: usize = @max(std.heap.page_size_max, 64 * 1024); | ... | @@ -51,10 +51,6 @@ const slab_len: usize = @max(std.heap.page_size_max, 64 * 1024); |
| 51 | /// Because of storing free list pointers, the minimum size class is 3. | 51 | /// Because of storing free list pointers, the minimum size class is 3. |
| 52 | const min_class = math.log2(@sizeOf(usize)); | 52 | const min_class = math.log2(@sizeOf(usize)); |
| 53 | const size_class_count = math.log2(slab_len) - min_class; | 53 | const size_class_count = math.log2(slab_len) - min_class; |
| 54 | /// When a freelist length exceeds this number of slabs, a `free` will rotate | | |
| 55 | /// up to `max_free_search` times before pushing. | | |
| 56 | const max_freelist_len = 255; | | |
| 57 | const max_free_search = 1; | | |
| 58 | /// Before mapping a fresh page, `alloc` will rotate this many times. | 54 | /// Before mapping a fresh page, `alloc` will rotate this many times. |
| 59 | const max_alloc_search = 1; | 55 | const max_alloc_search = 1; |
| 60 | | 56 | |
| ... | @@ -73,8 +69,6 @@ const Thread = struct { | ... | @@ -73,8 +69,6 @@ const Thread = struct { |
| 73 | next_addrs: [size_class_count]usize = @splat(0), | 69 | next_addrs: [size_class_count]usize = @splat(0), |
| 74 | /// For each size class, points to the freed pointer. | 70 | /// For each size class, points to the freed pointer. |
| 75 | frees: [size_class_count]usize = @splat(0), | 71 | frees: [size_class_count]usize = @splat(0), |
| 76 | /// For each size class, tracks the number of items in the freelist. | | |
| 77 | freelist_lens: [size_class_count]u8 = @splat(0), | | |
| 78 | | 72 | |
| 79 | fn lock() *Thread { | 73 | fn lock() *Thread { |
| 80 | var index = thread_index; | 74 | var index = thread_index; |
| ... | @@ -159,7 +153,6 @@ fn alloc(context: *anyopaque, len: usize, alignment: mem.Alignment, ra: usize) ? | ... | @@ -159,7 +153,6 @@ fn alloc(context: *anyopaque, len: usize, alignment: mem.Alignment, ra: usize) ? |
| 159 | // slab alignment here ensures the % slab len earlier catches the end of slots. | 153 | // slab alignment here ensures the % slab len earlier catches the end of slots. |
| 160 | const slab = PageAllocator.map(slab_len, .fromByteUnits(slab_len)) orelse return null; | 154 | const slab = PageAllocator.map(slab_len, .fromByteUnits(slab_len)) orelse return null; |
| 161 | t.next_addrs[class] = @intFromPtr(slab) + slot_size; | 155 | t.next_addrs[class] = @intFromPtr(slab) + slot_size; |
| 162 | t.freelist_lens[class] = 0; | | |
| 163 | return slab; | 156 | return slab; |
| 164 | } | 157 | } |
| 165 | | 158 | |
| ... | @@ -213,43 +206,12 @@ fn free(context: *anyopaque, memory: []u8, alignment: mem.Alignment, ra: usize) | ... | @@ -213,43 +206,12 @@ fn free(context: *anyopaque, memory: []u8, alignment: mem.Alignment, ra: usize) |
| 213 | } | 206 | } |
| 214 | | 207 | |
| 215 | const node: *usize = @alignCast(@ptrCast(memory.ptr)); | 208 | const node: *usize = @alignCast(@ptrCast(memory.ptr)); |
| 216 | var search_count: u8 = 0; | | |
| 217 | | | |
| 218 | var t = Thread.lock(); | | |
| 219 | | | |
| 220 | outer: while (true) { | | |
| 221 | const freelist_len = t.freelist_lens[class]; | | |
| 222 | if (freelist_len < max_freelist_len) { | | |
| 223 | @branchHint(.likely); | | |
| 224 | defer t.unlock(); | | |
| 225 | t.freelist_lens[class] = freelist_len +| @intFromBool((@intFromPtr(node) % slab_len) == 0); | | |
| 226 | node.* = t.frees[class]; | | |
| 227 | t.frees[class] = @intFromPtr(node); | | |
| 228 | return; | | |
| 229 | } | | |
| 230 | | 209 | |
| 231 | if (search_count >= max_free_search) { | 210 | const t = Thread.lock(); |
| 232 | defer t.unlock(); | 211 | defer t.unlock(); |
| 233 | t.freelist_lens[class] = freelist_len +| @intFromBool((@intFromPtr(node) % slab_len) == 0); | | |
| 234 | node.* = t.frees[class]; | | |
| 235 | t.frees[class] = @intFromPtr(node); | | |
| 236 | return; | | |
| 237 | } | | |
| 238 | | 212 | |
| 239 | t.unlock(); | 213 | node.* = t.frees[class]; |
| 240 | const cpu_count = getCpuCount(); | 214 | t.frees[class] = @intFromPtr(node); |
| 241 | assert(cpu_count != 0); | | |
| 242 | var index = thread_index; | | |
| 243 | while (true) { | | |
| 244 | index = (index + 1) % cpu_count; | | |
| 245 | t = &global.threads[index]; | | |
| 246 | if (t.mutex.tryLock()) { | | |
| 247 | thread_index = index; | | |
| 248 | search_count += 1; | | |
| 249 | continue :outer; | | |
| 250 | } | | |
| 251 | } | | |
| 252 | } | | |
| 253 | } | 215 | } |
| 254 | | 216 | |
| 255 | fn sizeClassIndex(len: usize, alignment: mem.Alignment) usize { | 217 | fn sizeClassIndex(len: usize, alignment: mem.Alignment) usize { |