diff options
author | 2021-08-23 02:29:07 -0700 | |
---|---|---|
committer | 2021-08-23 02:29:07 -0700 | |
commit | 8c6700792666b1d7a128095cd5cff392df68375c (patch) | |
tree | 2d094df1202fdf44587389e3e6f20967d6487dca /src/memory_allocator.zig | |
parent | e012efa1243d09fb1de282ac0a1fa6c8b07538a5 (diff) | |
download | bun-8c6700792666b1d7a128095cd5cff392df68375c.tar.gz bun-8c6700792666b1d7a128095cd5cff392df68375c.tar.zst bun-8c6700792666b1d7a128095cd5cff392df68375c.zip |
Use mimalloc for a 10% boost
Former-commit-id: 044e11d720bc6742dc53b30b4e88e8be7e76c419
Diffstat (limited to 'src/memory_allocator.zig')
-rw-r--r-- | src/memory_allocator.zig | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/memory_allocator.zig b/src/memory_allocator.zig new file mode 100644 index 000000000..3f5a7897c --- /dev/null +++ b/src/memory_allocator.zig @@ -0,0 +1,129 @@ +const mem = @import("std").mem; +const builtin = @import("std").builtin; +const std = @import("std"); + +const mimalloc = @import("./allocators/mimalloc.zig"); +const Allocator = mem.Allocator; +const assert = std.debug.assert; + +const CAllocator = struct { + comptime { + if (!builtin.link_libc) { + @compileError("C allocator is only available when linking against libc"); + } + } + pub const supports_malloc_size = true; + pub const malloc_size = mimalloc.mi_malloc_size; + pub const supports_posix_memalign = true; + + fn getHeader(ptr: [*]u8) *[*]u8 { + return @intToPtr(*[*]u8, @ptrToInt(ptr) - @sizeOf(usize)); + } + + fn alignedAlloc(len: usize, alignment: usize) ?[*]u8 { + if (supports_posix_memalign) { + // The posix_memalign only accepts alignment values that are a + // multiple of the pointer size + const eff_alignment = std.math.max(alignment, @sizeOf(usize)); + + var aligned_ptr: ?*c_void = undefined; + if (mimalloc.mi_posix_memalign(&aligned_ptr, eff_alignment, len) != 0) + return null; + + return @ptrCast([*]u8, aligned_ptr); + } + + // Thin wrapper around regular malloc, overallocate to account for + // alignment padding and store the orignal malloc()'ed pointer before + // the aligned address. + var unaligned_ptr = @ptrCast([*]u8, mimalloc.mi_malloc(len + alignment - 1 + @sizeOf(usize)) orelse return null); + const unaligned_addr = @ptrToInt(unaligned_ptr); + const aligned_addr = mem.alignForward(unaligned_addr + @sizeOf(usize), alignment); + var aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr); + getHeader(aligned_ptr).* = unaligned_ptr; + + return aligned_ptr; + } + + fn alignedFree(ptr: [*]u8) void { + if (supports_posix_memalign) { + return mimalloc.mi_free(ptr); + } + + const unaligned_ptr = getHeader(ptr).*; + mimalloc.mi_free(unaligned_ptr); + } + + fn alignedAllocSize(ptr: [*]u8) usize { + if (supports_posix_memalign) { + return malloc_size(ptr); + } + + const unaligned_ptr = getHeader(ptr).*; + const delta = @ptrToInt(ptr) - @ptrToInt(unaligned_ptr); + return malloc_size(unaligned_ptr) - delta; + } + + fn alloc( + allocator: *Allocator, + len: usize, + alignment: u29, + len_align: u29, + return_address: usize, + ) error{OutOfMemory}![]u8 { + _ = allocator; + _ = return_address; + assert(len > 0); + assert(std.math.isPowerOfTwo(alignment)); + + var ptr = alignedAlloc(len, alignment) orelse return error.OutOfMemory; + if (len_align == 0) { + return ptr[0..len]; + } + const full_len = init: { + if (supports_malloc_size) { + const s = alignedAllocSize(ptr); + assert(s >= len); + break :init s; + } + break :init len; + }; + return ptr[0..mem.alignBackwardAnyAlign(full_len, len_align)]; + } + + fn resize( + allocator: *Allocator, + buf: []u8, + buf_align: u29, + new_len: usize, + len_align: u29, + return_address: usize, + ) Allocator.Error!usize { + _ = allocator; + _ = buf_align; + _ = return_address; + if (new_len == 0) { + alignedFree(buf.ptr); + return 0; + } + if (new_len <= buf.len) { + return mem.alignAllocLen(buf.len, new_len, len_align); + } + if (supports_malloc_size) { + const full_len = alignedAllocSize(buf.ptr); + if (new_len <= full_len) { + return mem.alignAllocLen(full_len, new_len, len_align); + } + } + return error.OutOfMemory; + } +}; + +/// Supports the full Allocator interface, including alignment, and exploiting +/// `malloc_usable_size` if available. For an allocator that directly calls +/// `malloc`/`free`, see `raw_c_allocator`. +pub const c_allocator = &c_allocator_state; +var c_allocator_state = Allocator{ + .allocFn = CAllocator.alloc, + .resizeFn = CAllocator.resize, +}; |