aboutsummaryrefslogtreecommitdiff
path: root/src/mimalloc_arena.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-11-19 21:37:31 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-11-19 21:37:31 -0800
commit9c601542d0faf7d94c6828f3b7890e3eae9b957e (patch)
tree9a2541f9838c74c8cb9d603c43160d7d28c340d7 /src/mimalloc_arena.zig
parent7c7769a7c7db3b7932a2726adb9d64e011c1bed6 (diff)
downloadbun-9c601542d0faf7d94c6828f3b7890e3eae9b957e.tar.gz
bun-9c601542d0faf7d94c6828f3b7890e3eae9b957e.tar.zst
bun-9c601542d0faf7d94c6828f3b7890e3eae9b957e.zip
Update to Mimalloc v2.0.7
Diffstat (limited to '')
-rw-r--r--src/mimalloc_arena.zig124
1 files changed, 111 insertions, 13 deletions
diff --git a/src/mimalloc_arena.zig b/src/mimalloc_arena.zig
index a313c7dfe..5b2fa14e8 100644
--- a/src/mimalloc_arena.zig
+++ b/src/mimalloc_arena.zig
@@ -7,9 +7,88 @@ const Environment = @import("./env.zig");
const FeatureFlags = @import("./feature_flags.zig");
const Allocator = mem.Allocator;
const assert = std.debug.assert;
+const bun = @import("./global.zig");
+
+pub const GlobalArena = struct {
+ arena: Arena,
+ fallback_allocator: std.mem.Allocator,
+
+ pub fn initWithCapacity(capacity: usize, fallback: std.mem.Allocator) error{OutOfMemory}!GlobalArena {
+ const arena = try Arena.initWithCapacity(capacity);
+
+ return GlobalArena{
+ .arena = arena,
+ .fallback_allocator = fallback,
+ };
+ }
+
+ pub fn allocator(this: *GlobalArena) Allocator {
+ return std.mem.Allocator.init(this, alloc, resize, free);
+ }
+
+ fn alloc(
+ self: *GlobalArena,
+ len: usize,
+ ptr_align: u29,
+ len_align: u29,
+ return_address: usize,
+ ) error{OutOfMemory}![]u8 {
+ return self.arena.alloc(len, ptr_align, len_align, return_address) catch
+ return self.fallback_allocator.rawAlloc(len, ptr_align, len_align, return_address);
+ }
+
+ fn resize(
+ self: *GlobalArena,
+ buf: []u8,
+ buf_align: u29,
+ new_len: usize,
+ len_align: u29,
+ return_address: usize,
+ ) ?usize {
+ if (self.arena.ownsPtr(buf.ptr)) {
+ return self.arena.resize(buf, buf_align, new_len, len_align, return_address);
+ } else {
+ return self.fallback_allocator.rawResize(buf, buf_align, new_len, len_align, return_address);
+ }
+ }
+
+ fn free(
+ self: *GlobalArena,
+ buf: []u8,
+ buf_align: u29,
+ return_address: usize,
+ ) void {
+ if (self.arena.ownsPtr(buf.ptr)) {
+ return self.arena.free(buf, buf_align, return_address);
+ } else {
+ return self.fallback_allocator.rawFree(buf, buf_align, return_address);
+ }
+ }
+};
pub const Arena = struct {
- heap: ?*mimalloc.mi_heap_t = null,
+ heap: ?*mimalloc.Heap = null,
+ arena_id: mimalloc.ArenaID = -1,
+
+ pub fn initWithCapacity(capacity: usize) error{OutOfMemory}!Arena {
+ var arena_id: mimalloc.ArenaID = -1;
+
+ std.debug.assert(capacity >= 8 * 1024 * 1024); // mimalloc requires a minimum of 8MB
+ // which makes this not very useful for us!
+
+ if (!mimalloc.mi_manage_os_memory_ex(null, capacity, true, true, false, -1, true, &arena_id)) {
+ if (!mimalloc.mi_manage_os_memory_ex(null, capacity, false, false, false, -1, true, &arena_id)) {
+ return error.OutOfMemory;
+ }
+ }
+ std.debug.assert(arena_id != -1);
+
+ var heap = mimalloc.mi_heap_new_in_arena(arena_id) orelse return error.OutOfMemory;
+ return Arena{
+ .heap = heap,
+ .arena_id = arena_id,
+ };
+ }
/// Internally, mimalloc calls mi_heap_get_default()
/// to get the default heap.
@@ -30,13 +109,31 @@ pub const Arena = struct {
}
pub fn deinit(this: *Arena) void {
- mimalloc.mi_heap_destroy(this.heap);
+ mimalloc.mi_heap_destroy(this.heap.?);
this.heap = null;
}
pub fn dumpThreadStats(_: *Arena) void {
- mimalloc.mi_thread_stats_print_out(null, null);
+ const dump_fn = struct {
+ pub fn dump(textZ: [*:0]const u8, _: ?*anyopaque) callconv(.C) void {
+ const text = bun.span(textZ);
+ bun.Output.errorWriter().writeAll(text) catch {};
+ }
+ }.dump;
+ mimalloc.mi_thread_stats_print_out(dump_fn, null);
+ bun.Output.flush();
+ }
+
+ pub fn dumpStats(_: *Arena) void {
+ const dump_fn = struct {
+ pub fn dump(textZ: [*:0]const u8, _: ?*anyopaque) callconv(.C) void {
+ const text = bun.span(textZ);
+ bun.Output.errorWriter().writeAll(text) catch {};
+ }
+ }.dump;
+ mimalloc.mi_stats_print_out(dump_fn, null);
+ bun.Output.flush();
}
pub fn reset(this: *Arena) void {
@@ -49,7 +146,11 @@ pub const Arena = struct {
}
pub fn gc(this: Arena, force: bool) void {
- mimalloc.mi_heap_collect(this.heap, force);
+ mimalloc.mi_heap_collect(this.heap orelse return, force);
+ }
+
+ pub fn ownsPtr(this: Arena, ptr: *const anyopaque) bool {
+ return mimalloc.mi_heap_check_owned(this.heap.?, ptr);
}
// Copied from rust
@@ -59,19 +160,16 @@ pub const Arena = struct {
(alignment == MI_MAX_ALIGN_SIZE and size > (MI_MAX_ALIGN_SIZE / 2)));
}
- fn alignedAlloc(heap: *mimalloc.mi_heap_t, len: usize, alignment: usize) ?[*]u8 {
+ fn alignedAlloc(heap: *mimalloc.Heap, len: usize, alignment: usize) ?[*]u8 {
if (comptime FeatureFlags.log_allocations) std.debug.print("Malloc: {d}\n", .{len});
// this is the logic that posix_memalign does
- var ptr = if (mi_malloc_satisfies_alignment(alignment, len))
- mimalloc.mi_heap_malloc(heap, len)
- else
- mimalloc.mi_heap_malloc_aligned(heap, len, alignment);
+ var ptr = mimalloc.mi_heap_malloc_aligned(heap, len, alignment);
return @ptrCast([*]u8, ptr orelse null);
}
- fn alloc(
+ pub fn alloc(
arena: *anyopaque,
len: usize,
alignment: u29,
@@ -82,7 +180,7 @@ pub const Arena = struct {
assert(len > 0);
assert(std.math.isPowerOfTwo(alignment));
- var ptr = alignedAlloc(@ptrCast(*mimalloc.mi_heap_t, arena), len, alignment) orelse return error.OutOfMemory;
+ var ptr = alignedAlloc(@ptrCast(*mimalloc.Heap, arena), len, alignment) orelse return error.OutOfMemory;
if (len_align == 0) {
return ptr[0..len];
}
@@ -98,7 +196,7 @@ pub const Arena = struct {
}
}
- fn resize(
+ pub fn resize(
_: *anyopaque,
buf: []u8,
buf_align: u29,
@@ -121,7 +219,7 @@ pub const Arena = struct {
return null;
}
- fn free(
+ pub fn free(
_: *anyopaque,
buf: []u8,
buf_align: u29,