diff options
author | 2023-07-29 04:24:08 -0700 | |
---|---|---|
committer | 2023-07-29 04:24:08 -0700 | |
commit | c708cd8f2616b75eb1bfb9319a2d43a7c194d1bc (patch) | |
tree | 9df00826b972ae4e31d6bff49ac28890e562d4f0 | |
parent | bcb6dc78060f4309c08b63827b10e3d55632d647 (diff) | |
download | bun-c708cd8f2616b75eb1bfb9319a2d43a7c194d1bc.tar.gz bun-c708cd8f2616b75eb1bfb9319a2d43a7c194d1bc.tar.zst bun-c708cd8f2616b75eb1bfb9319a2d43a7c194d1bc.zip |
experiment: use bmalloc/libpas instead of mimalloc in most places
-rw-r--r-- | src/bmalloc_allocator.zig | 66 | ||||
-rw-r--r-- | src/boringssl.zig | 8 | ||||
-rw-r--r-- | src/bun.js/api/bun/subprocess.zig | 4 | ||||
-rw-r--r-- | src/bun.js/api/filesystem_router.zig | 2 | ||||
-rw-r--r-- | src/bun.js/api/server.zig | 2 | ||||
-rw-r--r-- | src/bun.js/base.zig | 50 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 15 | ||||
-rw-r--r-- | src/bun.js/bindings/exports.zig | 15 | ||||
-rw-r--r-- | src/bun.js/bindings/wtf-bindings.cpp | 42 | ||||
-rw-r--r-- | src/bun.zig | 19 | ||||
-rw-r--r-- | src/bun_js.zig | 4 | ||||
-rw-r--r-- | src/cli.zig | 3 | ||||
-rw-r--r-- | src/http_client_async.zig | 17 |
13 files changed, 165 insertions, 82 deletions
diff --git a/src/bmalloc_allocator.zig b/src/bmalloc_allocator.zig new file mode 100644 index 000000000..813246d9f --- /dev/null +++ b/src/bmalloc_allocator.zig @@ -0,0 +1,66 @@ +const mem = @import("std").mem; +const builtin = @import("std").builtin; +const std = @import("std"); + +pub const bmalloc = struct { + pub fn memalign(alignment: usize, size: usize) ?*anyopaque { + return bun__bmalloc__memalign(alignment, size); + } + pub fn free(ptr: *anyopaque) void { + return bun__bmalloc__free(ptr); + } + pub fn realloc(ptr: *anyopaque, size: usize) ?*anyopaque { + return bun__bmalloc__realloc(ptr, size); + } + pub fn allocatedSize(ptr: *anyopaque) usize { + return bun__bmalloc__size(ptr); + } + + extern fn bun__bmalloc__memalign(alignment: usize, size: usize) ?*anyopaque; + extern fn bun__bmalloc__free(*anyopaque) void; + extern fn bun__bmalloc__realloc(*anyopaque, usize) ?*anyopaque; + extern fn bun__bmalloc__size(*anyopaque) usize; + + pub extern fn bmalloc_try_allocate_zeroed(size: usize) ?*anyopaque; + pub extern fn bmalloc_deallocate(*anyopaque) void; + pub extern fn bmalloc_get_allocation_size(?*const anyopaque) usize; +}; +pub const free = bmalloc.free; + +const Allocator = mem.Allocator; +const assert = std.debug.assert; +const CAllocator = struct { + pub const supports_posix_memalign = true; + + fn alloc(_: *anyopaque, len: usize, log2_align: u8, _: usize) ?[*]u8 { + const alignment = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_align)); + // The posix_memalign only accepts alignment values that are a + // multiple of the pointer size + const eff_alignment = @max(alignment, @sizeOf(usize)); + return @ptrCast(bmalloc.memalign(eff_alignment, len)); + } + + fn resize(_: *anyopaque, buf: []u8, _: u8, new_len: usize, _: usize) bool { + return bmalloc.realloc(buf.ptr, new_len) != null; + } + + fn free( + _: *anyopaque, + buf: []u8, + _: u8, + _: usize, + ) void { + bmalloc.free(buf.ptr); + } + + pub const VTable = Allocator.VTable{ + .alloc = &alloc, + .resize = &resize, + .free = &CAllocator.free, + }; +}; + +pub const c_allocator = Allocator{ + .ptr = undefined, + .vtable = &CAllocator.VTable, +}; diff --git a/src/boringssl.zig b/src/boringssl.zig index a12c356d9..c53c0e7d7 100644 --- a/src/boringssl.zig +++ b/src/boringssl.zig @@ -60,18 +60,16 @@ pub fn initClient() *boring.SSL { // may result in deadlocks, crashes, or memory corruption. export fn OPENSSL_memory_alloc(size: usize) ?*anyopaque { - return bun.Mimalloc.mi_malloc(size); + return bun.bmalloc.bmalloc_try_allocate_zeroed(size); } // BoringSSL always expects memory to be zero'd export fn OPENSSL_memory_free(ptr: *anyopaque) void { - const len = bun.Mimalloc.mi_usable_size(ptr); - @memset(@as([*]u8, @ptrCast(ptr))[0..len], 0); - bun.Mimalloc.mi_free(ptr); + bun.bmalloc.bmalloc_deallocate(ptr); } export fn OPENSSL_memory_get_size(ptr: ?*const anyopaque) usize { - return bun.Mimalloc.mi_usable_size(ptr); + return bun.bmalloc.bmalloc_get_allocation_size(ptr); } test "load" { diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig index 4fb02b8af..f1fbd242a 100644 --- a/src/bun.js/api/bun/subprocess.zig +++ b/src/bun.js/api/bun/subprocess.zig @@ -1372,8 +1372,8 @@ pub const Subprocess = struct { return .zero; }, // stdout and stderr only uses allocator and default_max_buffer_size if they are pipes and not a array buffer - .stdout = Readable.init(stdio[std.os.STDOUT_FILENO], stdout_pipe[0], jsc_vm.allocator, default_max_buffer_size), - .stderr = Readable.init(stdio[std.os.STDERR_FILENO], stderr_pipe[0], jsc_vm.allocator, default_max_buffer_size), + .stdout = Readable.init(stdio[std.os.STDOUT_FILENO], stdout_pipe[0], bun.default_allocator, default_max_buffer_size), + .stderr = Readable.init(stdio[std.os.STDERR_FILENO], stderr_pipe[0], bun.default_allocator, default_max_buffer_size), .on_exit_callback = if (on_exit_callback != .zero) JSC.Strong.create(on_exit_callback, globalThis) else .{}, .is_sync = is_sync, }; diff --git a/src/bun.js/api/filesystem_router.zig b/src/bun.js/api/filesystem_router.zig index 216f66b7f..814f9c9b6 100644 --- a/src/bun.js/api/filesystem_router.zig +++ b/src/bun.js/api/filesystem_router.zig @@ -550,7 +550,7 @@ pub const MatchedRoute = struct { } if (this.needs_deinit) { if (this.route.pathname.len > 0 and bun.Mimalloc.mi_is_in_heap_region(this.route.pathname.ptr)) { - bun.Mimalloc.mi_free(bun.constStrToU8(this.route.pathname).ptr); + bun.default_allocator.free(bun.constStrToU8(this.route.pathname)); } this.params_list_holder.deinit(bun.default_allocator); diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 801745aee..28bcb45a4 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -5104,7 +5104,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { .config = config, .base_url_string_for_joining = bun.default_allocator.dupe(u8, strings.trim(config.base_url.href, "/")) catch unreachable, .vm = JSC.VirtualMachine.get(), - .allocator = Arena.getThreadlocalDefault(), + .allocator = bun.default_allocator, }; if (RequestContext.pool == null) { diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 579a0975a..0528eb8d1 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -1824,31 +1824,31 @@ pub const ArrayBuffer = extern struct { return this.value; } - // If it's not a mimalloc heap buffer, we're not going to call a deallocator - if (this.len > 0 and !bun.Mimalloc.mi_is_in_heap_region(this.ptr)) { - log("toJS but will never free: {d} bytes", .{this.len}); - - if (this.typed_array_type == .ArrayBuffer) { - return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy( - ctx, - this.ptr, - this.byte_len, - null, - null, - exception, - )); - } - - return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy( - ctx, - this.typed_array_type.toC(), - this.ptr, - this.byte_len, - null, - null, - exception, - )); - } + // // If it's not a mimalloc heap buffer, we're not going to call a deallocator + // if (this.len > 0 and !bun.Mimalloc.mi_is_in_heap_region(this.ptr)) { + // log("toJS but will never free: {d} bytes", .{this.len}); + + // if (this.typed_array_type == .ArrayBuffer) { + // return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy( + // ctx, + // this.ptr, + // this.byte_len, + // null, + // null, + // exception, + // )); + // } + + // return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy( + // ctx, + // this.typed_array_type.toC(), + // this.ptr, + // this.byte_len, + // null, + // null, + // exception, + // )); + // } return this.toJSUnchecked(ctx, exception); } diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 4f533b9d9..8be5d878f 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -727,6 +727,10 @@ pub const ZigString = extern struct { return untagged(this._unsafe_ptr_do_not_use)[0..@min(this.len, std.math.maxInt(u32))]; } + pub fn untaggedPtr(this: *const ZigString) [*]const u8 { + return untagged(this._unsafe_ptr_do_not_use); + } + pub fn dupe(this: ZigString, allocator: std.mem.Allocator) ![]const u8 { return try allocator.dupe(u8, this.slice()); } @@ -837,11 +841,12 @@ pub const ZigString = extern struct { } inline fn assertGlobal(this: *const ZigString) void { - if (comptime bun.Environment.allow_assert) { - std.debug.assert(this.len == 0 or - bun.Mimalloc.mi_is_in_heap_region(untagged(this._unsafe_ptr_do_not_use)) or - bun.Mimalloc.mi_check_owned(untagged(this._unsafe_ptr_do_not_use))); - } + _ = this; + // if (comptime bun.Environment.allow_assert) { + // std.debug.assert(this.len == 0 or + // bun.Mimalloc.mi_is_in_heap_region(untagged(this._unsafe_ptr_do_not_use)) or + // bun.Mimalloc.mi_check_owned(untagged(this._unsafe_ptr_do_not_use))); + // } } pub fn toValue(this: *const ZigString, global: *JSGlobalObject) JSValue { diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig index 20c110d52..ca70aa5ba 100644 --- a/src/bun.js/bindings/exports.zig +++ b/src/bun.js/bindings/exports.zig @@ -243,22 +243,17 @@ const Mimalloc = @import("../../allocators/mimalloc.zig"); export fn ZigString__free(raw: [*]const u8, len: usize, allocator_: ?*anyopaque) void { var allocator: std.mem.Allocator = @as(*std.mem.Allocator, @ptrCast(@alignCast(allocator_ orelse return))).*; - var ptr = ZigString.init(raw[0..len]).slice().ptr; - if (comptime Environment.allow_assert) { - std.debug.assert(Mimalloc.mi_is_in_heap_region(ptr)); - } + var ptr = ZigString.init(raw[0..len]).untaggedPtr(); + // if (comptime Environment.allow_assert) { + // std.debug.assert(Mimalloc.mi_is_in_heap_region(ptr)); + // } var str = ptr[0..len]; allocator.free(str); } export fn ZigString__free_global(ptr: [*]const u8, len: usize) void { - var untagged = @as(*anyopaque, @ptrFromInt(@intFromPtr(ZigString.init(ptr[0..len]).slice().ptr))); - if (comptime Environment.allow_assert) { - std.debug.assert(Mimalloc.mi_is_in_heap_region(ptr)); - } - // we must untag the string pointer - Mimalloc.mi_free(untagged); + bun.free(@constCast(ZigString.init(ptr[0..len]).untaggedPtr())); } export fn Zig__getAPIGlobals(count: *usize) [*]JSC.C.JSClassRef { diff --git a/src/bun.js/bindings/wtf-bindings.cpp b/src/bun.js/bindings/wtf-bindings.cpp index 5c0e593d7..5bc37467a 100644 --- a/src/bun.js/bindings/wtf-bindings.cpp +++ b/src/bun.js/bindings/wtf-bindings.cpp @@ -2,7 +2,47 @@ #include "wtf/text/Base64.h" #include "wtf/StackTrace.h" -#include "wtf/dtoa.h" +#include "bmalloc/bmalloc.h" + +extern "C" void bun__bmalloc__init() +{ + WTF::initializeMainThread(); +} + +extern "C" void* bun__bmalloc__memalign(size_t alignment, size_t size) +{ + return bmalloc::api::tryMemalign(alignment, size); +} + +extern "C" void bun__bmalloc__free(void* ptr) +{ + bmalloc::api::free(ptr); +} + +extern "C" void* bun__bmalloc__realloc(void* ptr, size_t size) +{ + if (bmalloc_get_allocation_size(ptr) >= size) + return (void*)ptr; + + return nullptr; +} + +extern "C" size_t bun__bmalloc__size(void* ptr) +{ + return bmalloc_get_allocationpub fn isHeapMemory(memory + : anytype) bool + { + if (comptime use_mimalloc) { + const Memory = @TypeOf(memory); + if (comptime std.meta.trait.isSingleItemPtr(Memory)) { + return Mimalloc.mi_is_in_heap_region(memory); + } + return Mimalloc.mi_is_in_heap_region(std.mem.sliceAsBytes(memory).ptr); + } + return false; + } + _size(ptr); +} extern "C" double WTF__parseDouble(const LChar* string, size_t length, size_t* position) { diff --git a/src/bun.zig b/src/bun.zig index 8dd888b69..bfe6cc047 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -3,10 +3,7 @@ pub const Environment = @import("env.zig"); pub const use_mimalloc = !Environment.isTest; -pub const default_allocator: std.mem.Allocator = if (!use_mimalloc) - std.heap.c_allocator -else - @import("./memory_allocator.zig").c_allocator; +pub const default_allocator: std.mem.Allocator = @import("./bmalloc_allocator.zig").c_allocator; pub const huge_allocator: std.mem.Allocator = if (!use_mimalloc) std.heap.c_allocator @@ -667,18 +664,8 @@ pub fn once(comptime function: anytype, comptime ReturnType: type) ReturnType { return Result.execute(); } - -pub fn isHeapMemory(memory: anytype) bool { - if (comptime use_mimalloc) { - const Memory = @TypeOf(memory); - if (comptime std.meta.trait.isSingleItemPtr(Memory)) { - return Mimalloc.mi_is_in_heap_region(memory); - } - return Mimalloc.mi_is_in_heap_region(std.mem.sliceAsBytes(memory).ptr); - } - return false; -} - +pub const free = @import("./bmalloc_allocator.zig").free; +pub const bmalloc = @import("./bmalloc_allocator.zig").bmalloc; pub const Mimalloc = @import("./allocators/mimalloc.zig"); pub inline fn isSliceInBuffer(slice: []const u8, buffer: []const u8) bool { diff --git a/src/bun_js.zig b/src/bun_js.zig index 79f1c2596..8763f9960 100644 --- a/src/bun_js.zig +++ b/src/bun_js.zig @@ -145,7 +145,7 @@ pub const Run = struct { run = .{ .vm = try VirtualMachine.init( - arena.allocator(), + bun.default_allocator, ctx.args, null, ctx.log, @@ -163,7 +163,7 @@ pub const Run = struct { vm.preload = ctx.preloads; vm.argv = ctx.passthrough; vm.arena = &run.arena; - vm.allocator = arena.allocator(); + vm.allocator = bun.default_allocator; b.options.install = ctx.install; b.resolver.opts.install = ctx.install; diff --git a/src/cli.zig b/src/cli.zig index 1debd9254..a35b583b1 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -1030,6 +1030,7 @@ pub const Command = struct { } }; + extern fn bun__bmalloc__init() void; pub fn which() Tag { var args_iter = ArgsIterator{ .buf = std.os.argv }; // first one is the executable name @@ -1153,6 +1154,8 @@ pub const Command = struct { // _ = BunxCommand; } + bun__bmalloc__init(); + if (try bun.StandaloneModuleGraph.fromExecutable(bun.default_allocator)) |graph| { var ctx = Command.Context{ .args = std.mem.zeroes(Api.TransformOptions), diff --git a/src/http_client_async.zig b/src/http_client_async.zig index d49f7814d..c6132d100 100644 --- a/src/http_client_async.zig +++ b/src/http_client_async.zig @@ -35,8 +35,7 @@ const uws = bun.uws; pub const MimeType = @import("./http/mime_type.zig"); pub const URLPath = @import("./http/url_path.zig"); // This becomes Arena.allocator -pub var default_allocator: std.mem.Allocator = undefined; -var default_arena: Arena = undefined; +pub const default_allocator = bun.default_allocator; pub var http_thread: HTTPThread = undefined; const HiveArray = @import("./hive_array.zig").HiveArray; const Batch = NetworkThread.Batch; @@ -627,8 +626,7 @@ pub const HTTPThread = struct { pub fn onStart(_: FakeStruct) void { Output.Source.configureNamedThread("HTTP Client"); - default_arena = Arena.init() catch unreachable; - default_allocator = default_arena.allocator(); + var loop = uws.Loop.create(struct { pub fn wakeup(_: *uws.Loop) callconv(.C) void { http_thread.drainEvents(); @@ -869,7 +867,7 @@ pub inline fn getAllocator() std.mem.Allocator { } pub inline fn cleanup(force: bool) void { - default_arena.gc(force); + _ = force; } pub const Headers = @import("./http/headers.zig"); @@ -2475,15 +2473,6 @@ pub fn done(this: *HTTPClient, comptime is_ssl: bool, ctx: *NewHTTPContext(is_ss this.state.request_stage = .done; this.state.stage = .done; this.proxy_tunneling = false; - if (comptime print_every > 0) { - print_every_i += 1; - if (print_every_i % print_every == 0) { - Output.prettyln("Heap stats for HTTP thread\n", .{}); - Output.flush(); - default_arena.dumpThreadStats(); - print_every_i = 0; - } - } callback.run(result); } } |