diff --git a/src/engine/VkAllocator.zig b/src/engine/VkAllocator.zig index d4b9711..7afd53c 100644 --- a/src/engine/VkAllocator.zig +++ b/src/engine/VkAllocator.zig @@ -4,8 +4,9 @@ const std = @import("std"); const vk = @import("vulkan"); allocator: std.mem.Allocator, -allocations: std.AutoHashMapUnmanaged(?*anyopaque, usize) = .empty, +allocations: std.AutoHashMapUnmanaged(*anyopaque, usize) = .empty, mutex: std.Thread.Mutex = .{}, +allocated_bytes: usize = 0, interface: vk.AllocationCallbacks, @@ -15,6 +16,8 @@ interface: vk.AllocationCallbacks, // with the same, relatively big alignment and hope for the best. const actual_alignment: std.mem.Alignment = .@"16"; +const log = std.log.scoped(.vk_allocator); + pub fn init(allocator: std.mem.Allocator) !*VkAllocator { // NOTE We allocate the structure to pin its address. const self = try allocator.create(VkAllocator); @@ -33,6 +36,19 @@ pub fn init(allocator: std.mem.Allocator) !*VkAllocator { pub fn deinit(self: *VkAllocator) void { std.log.debug("Deinitializing {*}", .{self}); + if (self.allocated_bytes > 0) { + log.warn("{d} byte(s) still allocated while deinitializing", .{self.allocated_bytes}); + } + if (self.allocations.size > 0) { + log.warn("{d} allocation(s) still tracked while deinitializing", .{self.allocations.size}); + var it = self.allocations.iterator(); + var index: usize = 0; + while (it.next()) |entry| : (index += 1) { + log.warn("Leaked allocation ({d}/{d}) at 0x{x} of {d} byte(s)", .{ index + 1, self.allocations.size, @intFromPtr(entry.key_ptr.*), entry.value_ptr.* }); + const memory = @as([*]align(actual_alignment.toByteUnits()) u8, @ptrCast(@alignCast(entry.key_ptr.*)))[0..entry.value_ptr.*]; + self.allocator.free(memory); + } + } const allocator = self.allocator; @@ -60,6 +76,8 @@ fn allocationFunction( const memory = self.allocator.alignedAlloc(u8, actual_alignment, size) catch return null; self.allocations.putAssumeCapacity(memory.ptr, size); + self.allocated_bytes += size; + //log.debug("Allocated {d} bytes(s) at 0x{x}", .{ size, @intFromPtr(memory.ptr) }); return memory.ptr; } @@ -94,11 +112,13 @@ fn reallocationFunction( std.debug.assert(std.mem.isAligned(@intFromPtr(memory.ptr), alignment)); if (maybe_p_original) |p_original| { - const removed = self.allocations.remove(p_original); - std.debug.assert(removed); + const old_size = self.allocations.fetchRemove(p_original).?.value; + self.allocated_bytes -= old_size; } self.allocations.putAssumeCapacityNoClobber(memory.ptr, size); + self.allocated_bytes += size; + //log.debug("Reallocated into {d} bytes(s) at 0x{x} from 0x{x}", .{ size, @intFromPtr(memory.ptr), @intFromPtr(maybe_p_original) }); return memory.ptr; } @@ -114,6 +134,7 @@ fn freeFunction( defer self.mutex.unlock(); const size = self.allocations.fetchRemove(p_memory).?.value; + self.allocated_bytes -= size; const memory = @as([*]align(actual_alignment.toByteUnits()) u8, @ptrCast(@alignCast(p_memory)))[0..size]; self.allocator.free(memory);