diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e73d0d0..8924a73 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,8 @@ jobs: - name: Run tests run: zig build test --summary all + - run: apt-get update && apt-get install -y libjemalloc-dev + - name: Build release binary run: zig build --release=fast --summary all diff --git a/Dockerfile b/Dockerfile index 6e68ba3..d1dee9a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:24.04 -RUN apt-get update && apt-get install -y glibc-tools +RUN apt-get update && apt-get install -y glibc-tools libjemalloc2 RUN useradd -m -s /bin/bash -u 6081 acoustid diff --git a/src/jemalloc.zig b/src/jemalloc.zig new file mode 100644 index 0000000..a91ea11 --- /dev/null +++ b/src/jemalloc.zig @@ -0,0 +1,49 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const c = @cImport({ + @cInclude("jemalloc/jemalloc.h"); +}); + +pub const allocator = Allocator{ + .ptr = undefined, + .vtable = &.{ + .alloc = alloc, + .resize = resize, + .free = free, + }, +}; + +fn alloc(_: *anyopaque, n: usize, log2_align: u8, return_address: usize) ?[*]u8 { + _ = return_address; + + const alignment = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_align)); + const ptr = c.je_aligned_alloc(alignment, n) orelse return null; + return @ptrCast(ptr); +} + +fn resize( + _: *anyopaque, + buf: []u8, + log2_buf_align: u8, + new_len: usize, + return_address: usize, +) bool { + _ = log2_buf_align; + _ = return_address; + + if (new_len <= buf.len) + return true; + + return new_len <= c.je_malloc_usable_size(buf.ptr); +} + +fn free(_: *anyopaque, buf: []u8, log2_buf_align: u8, return_address: usize) void { + _ = log2_buf_align; + _ = return_address; + c.je_free(buf.ptr); +} + +test "basic" { + const buf = try allocator.alloc(u8, 256); + defer allocator.free(buf); +} diff --git a/src/main.zig b/src/main.zig index 6d01443..4b2845c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,6 +7,7 @@ const Scheduler = @import("utils/Scheduler.zig"); const MultiIndex = @import("MultiIndex.zig"); const server = @import("server.zig"); const metrics = @import("metrics.zig"); +const jemalloc = @import("jemalloc.zig"); pub const std_options = .{ .log_level = .debug, @@ -41,7 +42,7 @@ pub fn main() !void { var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{}; defer _ = gpa.deinit(); - const allocator = if (builtin.mode == .ReleaseFast and !builtin.is_test) std.heap.c_allocator else gpa.allocator(); + const allocator = if (builtin.mode == .ReleaseFast and !builtin.is_test) jemalloc.allocator else gpa.allocator(); var args = try zul.CommandLineArgs.parse(allocator); defer args.deinit();