diff --git a/build.zig b/build.zig index e2b0e45..e973a3e 100644 --- a/build.zig +++ b/build.zig @@ -148,6 +148,13 @@ pub fn build(b: *std.build.Builder) !void { b.option(bool, "allocation_info", "Enable use of debugging allocator and info logging.") orelse false, ); + const max_bytes_str = b.option([]const u8, "max_bytes_allocated", "Maximum amount of bytes to allocate before we exit. Zero for unlimited allocations. Only takes effect when allocation_info=true") orelse "0"; + exe.addBuildOption( + usize, + "max_bytes_allocated", + try std.fmt.parseInt(usize, max_bytes_str, 10), + ); + exe.addPackage(.{ .name = "known-folders", .path = "src/known-folders/known-folders.zig" }); exe.setTarget(target); diff --git a/src/debug_allocator.zig b/src/debug_allocator.zig index 29f2591..eac1fe5 100644 --- a/src/debug_allocator.zig +++ b/src/debug_allocator.zig @@ -35,9 +35,15 @@ pub const AllocationInfo = struct { deallocation_count: usize = 0, deallocation_total: usize = 0, + peak_allocated: usize = 0, + reallocation_stats: Stats = Stats{}, shrink_stats: Stats = Stats{}, + fn currentlyAllocated(self: AllocationInfo) usize { + return self.allocation_stats.total + self.reallocation_stats.total - self.deallocation_total - self.shrink_stats.total; + } + pub fn format( self: AllocationInfo, comptime fmt: []const u8, @@ -51,7 +57,7 @@ pub const AllocationInfo = struct { out_stream, \\------------------------------------------ Allocation info ------------------------------------------ \\{} total allocations (total: {d:.2} MB, mean: {d:.2} MB, std. dev: {d:.2} MB), {} deallocations - \\{} current allocations ({d:.2} MB) + \\{} current allocations ({d:.2} MB), peak mem usage: {d:.2} MB \\{} reallocations (total: {d:.2} MB, mean: {d:.2} MB, std. dev: {d:.2} MB) \\{} shrinks (total: {d:.2} MB, mean: {d:.2} MB, std. dev: {d:.2} MB) \\----------------------------------------------------------------------------------------------------- @@ -63,7 +69,8 @@ pub const AllocationInfo = struct { toMB(self.allocation_stats.stdDev()), self.deallocation_count, self.allocation_stats.count - self.deallocation_count, - toMB(self.allocation_stats.total + self.reallocation_stats.total - self.deallocation_total - self.shrink_stats.total), + toMB(self.currentlyAllocated()), + toMB(self.peak_allocated), self.reallocation_stats.count, toMB(self.reallocation_stats.total), toMB(self.reallocation_stats.mean), @@ -79,14 +86,16 @@ pub const AllocationInfo = struct { base_allocator: *std.mem.Allocator, info: AllocationInfo, +max_bytes: usize, // Interface implementation allocator: std.mem.Allocator, -pub fn init(base_allocator: *std.mem.Allocator) DebugAllocator { +pub fn init(base_allocator: *std.mem.Allocator, max_bytes: usize) DebugAllocator { return .{ .base_allocator = base_allocator, .info = .{}, + .max_bytes = max_bytes, .allocator = .{ .reallocFn = realloc, .shrinkFn = shrink, @@ -104,6 +113,16 @@ fn realloc(allocator: *std.mem.Allocator, old_mem: []u8, old_align: u29, new_siz } else if (new_size < old_mem.len) { self.info.shrink_stats.addSample(old_mem.len - new_size); } + + const curr_allocs = self.info.currentlyAllocated(); + if (self.max_bytes != 0 and curr_allocs >= self.max_bytes) { + std.debug.warn("Exceeded maximum bytes {}, exiting.\n", .{self.max_bytes}); + std.process.exit(1); + } + + if (curr_allocs > self.info.peak_allocated) { + self.info.peak_allocated = curr_allocs; + } return data; } diff --git a/src/main.zig b/src/main.zig index e993f38..3732310 100644 --- a/src/main.zig +++ b/src/main.zig @@ -997,7 +997,7 @@ pub fn main() anyerror!void { if (build_options.allocation_info) { // TODO: Use a better debugging allocator, track size in bytes, memory reserved etc.. // Initialize the leak counting allocator. - debug_alloc_state = DebugAllocator.init(allocator); + debug_alloc_state = DebugAllocator.init(allocator, build_options.max_bytes_allocated); allocator = &debug_alloc_state.allocator; }