Remove allocation checks in optimized release builds
This commit is contained in:
parent
341710bfbc
commit
d378939f30
|
@ -1,3 +1,5 @@
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const coral = @import("coral");
|
const coral = @import("coral");
|
||||||
|
|
||||||
const ext = @import("./ext.zig");
|
const ext = @import("./ext.zig");
|
||||||
|
@ -8,11 +10,19 @@ const std = @import("std");
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
const AllocationInfo = struct {
|
const AllocationInfo = struct {
|
||||||
trace: std.debug.Trace,
|
trace: AllocationTrace,
|
||||||
next_info: ?*AllocationInfo,
|
next_info: ?*AllocationInfo,
|
||||||
size: usize,
|
size: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
const AllocationTrace = std.debug.ConfigurableTrace(2, 4, switch (builtin.mode) {
|
||||||
|
.Debug, .ReleaseSafe => true,
|
||||||
|
.ReleaseFast, .ReleaseSmall => false,
|
||||||
|
});
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -29,23 +39,40 @@ const Context = struct {
|
||||||
/// *Note* the returned buffer must be deallocated with [deallocate] before program exit or it will cause a memory
|
/// *Note* the returned buffer must be deallocated with [deallocate] before program exit or it will cause a memory
|
||||||
/// leak.
|
/// leak.
|
||||||
///
|
///
|
||||||
|
/// *Note* allocation checks are disabled in release builds optimized for speed or size.
|
||||||
|
///
|
||||||
fn allocate(self: *Context, size: usize, return_address: usize) ?[]u8 {
|
fn allocate(self: *Context, size: usize, return_address: usize) ?[]u8 {
|
||||||
const allocation_info_size = @sizeOf(AllocationInfo);
|
switch (builtin.mode) {
|
||||||
const total_allocation_size = allocation_info_size + size;
|
.Debug, .ReleaseSafe => {
|
||||||
const allocation = ext.SDL_malloc(total_allocation_size) orelse return null;
|
const allocation_info_size = @sizeOf(AllocationInfo);
|
||||||
const allocation_info = @ptrCast(*AllocationInfo, @alignCast(@alignOf(AllocationInfo), allocation));
|
const total_allocation_size = allocation_info_size + size;
|
||||||
|
const allocation = ext.SDL_malloc(total_allocation_size) orelse return null;
|
||||||
|
const allocation_info = @ptrCast(*AllocationInfo, @alignCast(@alignOf(AllocationInfo), allocation));
|
||||||
|
|
||||||
allocation_info.* = .{
|
allocation_info.* = .{
|
||||||
.size = size,
|
.size = size,
|
||||||
.next_info = self.allocation_info_head,
|
.next_info = self.allocation_info_head,
|
||||||
.trace = .{},
|
.trace = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
allocation_info.trace.addAddr(return_address, "");
|
allocation_info.trace.addAddr(return_address, "");
|
||||||
|
|
||||||
self.allocation_info_head = allocation_info;
|
self.allocation_info_head = allocation_info;
|
||||||
|
|
||||||
return @ptrCast([*]u8, allocation)[allocation_info_size .. total_allocation_size];
|
return @ptrCast([*]u8, allocation)[allocation_info_size .. total_allocation_size];
|
||||||
|
},
|
||||||
|
|
||||||
|
.ReleaseFast, .ReleaseSmall => {
|
||||||
|
return @ptrCast([*]u8, ext.SDL_malloc(size) orelse return null)[0 .. size];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
fn allocation_info_of(allocation: [*]u8) *AllocationInfo {
|
||||||
|
return @intToPtr(*AllocationInfo, @ptrToInt(allocation) - @sizeOf(AllocationInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -54,40 +81,50 @@ const Context = struct {
|
||||||
/// *Note* the pointer and length of `allocation` must match valid values known to `allocator` otherwise safety-
|
/// *Note* the pointer and length of `allocation` must match valid values known to `allocator` otherwise safety-
|
||||||
/// checked behavior will occur.
|
/// checked behavior will occur.
|
||||||
///
|
///
|
||||||
|
/// *Note* allocation checks are disabled in release builds optimized for speed or size.
|
||||||
|
///
|
||||||
fn deallocate(self: *Context, allocation: []u8) void {
|
fn deallocate(self: *Context, allocation: []u8) void {
|
||||||
const target_allocation_info = @intToPtr(*AllocationInfo, @ptrToInt(allocation.ptr) - @sizeOf(AllocationInfo));
|
switch (builtin.mode) {
|
||||||
|
.Debug, .ReleaseSafe => {
|
||||||
|
const target_allocation_info = allocation_info_of(allocation.ptr);
|
||||||
|
|
||||||
if (target_allocation_info.size != allocation.len) {
|
if (target_allocation_info.size != allocation.len) {
|
||||||
@panic("incorrect allocation length for deallocating");
|
@panic("incorrect allocation length for deallocating");
|
||||||
}
|
|
||||||
|
|
||||||
if (self.allocation_info_head) |allocation_info_head| {
|
|
||||||
if (target_allocation_info == allocation_info_head) {
|
|
||||||
self.allocation_info_head = allocation_info_head.next_info;
|
|
||||||
|
|
||||||
ext.SDL_free(target_allocation_info);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var previous_allocation_info = allocation_info_head;
|
|
||||||
var current_allocation_info = allocation_info_head.next_info;
|
|
||||||
|
|
||||||
while (current_allocation_info) |allocation_info| {
|
|
||||||
if (allocation_info == target_allocation_info) {
|
|
||||||
previous_allocation_info.next_info = allocation_info.next_info;
|
|
||||||
|
|
||||||
ext.SDL_free(target_allocation_info);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_allocation_info = allocation_info;
|
if (self.allocation_info_head) |allocation_info_head| {
|
||||||
current_allocation_info = allocation_info.next_info;
|
if (target_allocation_info == allocation_info_head) {
|
||||||
}
|
self.allocation_info_head = allocation_info_head.next_info;
|
||||||
}
|
|
||||||
|
|
||||||
@panic("incorrect allocation address for deallocating");
|
ext.SDL_free(target_allocation_info);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var previous_allocation_info = allocation_info_head;
|
||||||
|
var current_allocation_info = allocation_info_head.next_info;
|
||||||
|
|
||||||
|
while (current_allocation_info) |allocation_info| {
|
||||||
|
if (allocation_info == target_allocation_info) {
|
||||||
|
previous_allocation_info.next_info = allocation_info.next_info;
|
||||||
|
|
||||||
|
ext.SDL_free(target_allocation_info);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_allocation_info = allocation_info;
|
||||||
|
current_allocation_info = allocation_info.next_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@panic("incorrect allocation address for deallocating");
|
||||||
|
},
|
||||||
|
|
||||||
|
.ReleaseFast, .ReleaseSmall => {
|
||||||
|
ext.SDL_free(allocation.ptr);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -105,41 +142,52 @@ const Context = struct {
|
||||||
/// *Note* the allocation referenced by `allocation` should be considered invalid once the function returns,
|
/// *Note* the allocation referenced by `allocation` should be considered invalid once the function returns,
|
||||||
/// discarding it in favor of the return value.
|
/// discarding it in favor of the return value.
|
||||||
///
|
///
|
||||||
|
/// *Note* allocation checks are disabled in release builds optimized for speed or size.
|
||||||
|
///
|
||||||
fn reallocate(self: *Context, allocation: []u8, size: usize) ?[]u8 {
|
fn reallocate(self: *Context, allocation: []u8, size: usize) ?[]u8 {
|
||||||
const allocation_info_size = @sizeOf(AllocationInfo);
|
switch (builtin.mode) {
|
||||||
const target_allocation_info = @intToPtr(*AllocationInfo, @ptrToInt(allocation.ptr) - allocation_info_size);
|
.Debug, .ReleaseSafe => {
|
||||||
|
const target_allocation_info = allocation_info_of(allocation.ptr);
|
||||||
|
|
||||||
if (target_allocation_info.size != allocation.len) {
|
if (target_allocation_info.size != allocation.len) {
|
||||||
@panic("incorrect allocation length for reallocating");
|
@panic("incorrect allocation length for reallocating");
|
||||||
}
|
|
||||||
|
|
||||||
if (self.allocation_info_head) |allocation_info_head| {
|
|
||||||
if (target_allocation_info == allocation_info_head) {
|
|
||||||
self.allocation_info_head = allocation_info_head.next_info;
|
|
||||||
|
|
||||||
return @ptrCast([*]u8, ext.SDL_realloc(target_allocation_info, size) orelse {
|
|
||||||
return null;
|
|
||||||
})[allocation_info_size .. allocation_info_size + size];
|
|
||||||
}
|
|
||||||
|
|
||||||
var previous_allocation_info = allocation_info_head;
|
|
||||||
var current_allocation_info = allocation_info_head.next_info;
|
|
||||||
|
|
||||||
while (current_allocation_info) |allocation_info| {
|
|
||||||
if (allocation_info == target_allocation_info) {
|
|
||||||
previous_allocation_info.next_info = allocation_info.next_info;
|
|
||||||
|
|
||||||
return @ptrCast([*]u8, ext.SDL_realloc(target_allocation_info, size) orelse {
|
|
||||||
return null;
|
|
||||||
})[allocation_info_size .. allocation_info_size + size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_allocation_info = allocation_info;
|
const allocation_info_size = @sizeOf(AllocationInfo);
|
||||||
current_allocation_info = allocation_info.next_info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@panic("incorrect allocation address for reallocating");
|
if (self.allocation_info_head) |allocation_info_head| {
|
||||||
|
if (target_allocation_info == allocation_info_head) {
|
||||||
|
self.allocation_info_head = allocation_info_head.next_info;
|
||||||
|
|
||||||
|
return @ptrCast([*]u8, ext.SDL_realloc(target_allocation_info, size) orelse {
|
||||||
|
return null;
|
||||||
|
})[allocation_info_size .. allocation_info_size + size];
|
||||||
|
}
|
||||||
|
|
||||||
|
var previous_allocation_info = allocation_info_head;
|
||||||
|
var current_allocation_info = allocation_info_head.next_info;
|
||||||
|
|
||||||
|
while (current_allocation_info) |allocation_info| {
|
||||||
|
if (allocation_info == target_allocation_info) {
|
||||||
|
previous_allocation_info.next_info = allocation_info.next_info;
|
||||||
|
|
||||||
|
return @ptrCast([*]u8, ext.SDL_realloc(target_allocation_info, size) orelse {
|
||||||
|
return null;
|
||||||
|
})[allocation_info_size .. allocation_info_size + size];
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_allocation_info = allocation_info;
|
||||||
|
current_allocation_info = allocation_info.next_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@panic("incorrect allocation address for reallocating");
|
||||||
|
},
|
||||||
|
|
||||||
|
.ReleaseFast, .ReleaseSmall => {
|
||||||
|
return @ptrCast([*]u8, ext.SDL_realloc(allocation.ptr, size) orelse return null)[0 .. size];
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,14 +224,23 @@ pub const allocator = coral.io.Allocator.bind(Context, &context, struct {
|
||||||
/// alive and reports the stack traces of any detected allocations to stderr along with the allocation address and
|
/// alive and reports the stack traces of any detected allocations to stderr along with the allocation address and
|
||||||
/// length.
|
/// length.
|
||||||
///
|
///
|
||||||
|
/// *Note* this function becomes a no-op in release builds optimized for speed or size.
|
||||||
|
///
|
||||||
pub fn trace_leaks() void {
|
pub fn trace_leaks() void {
|
||||||
var current_allocation_info = context.allocation_info_head;
|
switch (builtin.mode) {
|
||||||
|
.Debug, .ReleaseSafe => {
|
||||||
|
var current_allocation_info = context.allocation_info_head;
|
||||||
|
|
||||||
while (current_allocation_info) |allocation_info| : (current_allocation_info = allocation_info.next_info) {
|
while (current_allocation_info) |allocation_info| : (current_allocation_info = allocation_info.next_info) {
|
||||||
std.debug.print("{d} byte leak at 0x{x} detected: {}", .{
|
std.debug.print("{d} byte leak at 0x{x} detected:\n", .{
|
||||||
allocation_info.size,
|
allocation_info.size,
|
||||||
@ptrToInt(allocation_info) + @sizeOf(AllocationInfo),
|
@ptrToInt(allocation_info) + @sizeOf(AllocationInfo),
|
||||||
allocation_info.trace
|
});
|
||||||
});
|
|
||||||
|
allocation_info.trace.dump();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.ReleaseFast, .ReleaseSmall => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue