Skip to content

Instantly share code, notes, and snippets.

@benoitjacquier
Created December 10, 2018 21:31
Show Gist options
  • Save benoitjacquier/62299cb6ab923641c52d71ae8efa06eb to your computer and use it in GitHub Desktop.
Save benoitjacquier/62299cb6ab923641c52d71ae8efa06eb to your computer and use it in GitHub Desktop.
allocator with leaktracker using odin-lang
package leaktracker
import "core:fmt"
import "core:runtime"
import "core:mem"
import "core:os"
Alloc_Header_Magic :: u32(0xAC019876);
Alloc_Header :: struct {
magic: u32,
location: runtime.Source_Code_Location,
size: int,
alloc_uid: u64,
prev,next: ^Alloc_Header,
}
Allocator_Magic :: u32(0xAC069877);
Allocator :: struct {
magic: u32,
thread_id: int,
head: ^Alloc_Header,
alloc_uid: u64,
curr_alloc_count: u64,
peak_alloc_count: u64,
total_alloc_count: u64,
curr_mem_alloc: u64,
peak_mem_alloc: u64,
}
_internal_alloc :: proc "contextless" (allocator: ^Allocator, size: int, loc : runtime.Source_Code_Location ) -> rawptr {
size_with_header := size+size_of(Alloc_Header);
ptr := (uintptr)(os.heap_alloc(size_with_header));
new_header := (^Alloc_Header)(ptr);
new_header.magic = Alloc_Header_Magic;
new_header.location = loc;
new_header.size = size;
new_header.next = allocator.head;
allocator.alloc_uid +=1;
new_header.alloc_uid = allocator.alloc_uid;
if allocator.head!=nil {
allocator.head.prev = new_header;
}
allocator.head = new_header;
allocator.curr_alloc_count += 1;
allocator.peak_alloc_count = max(allocator.curr_alloc_count, allocator.peak_alloc_count);
allocator.total_alloc_count += 1;
allocator.curr_mem_alloc += u64(size);
allocator.peak_mem_alloc = max(allocator.curr_mem_alloc, allocator.peak_mem_alloc);
real_ptr := (rawptr)(ptr + (uintptr)(size_of(Alloc_Header)));
return real_ptr;
}
_internal_free :: proc "contextless" (allocator: ^Allocator, old_memory: rawptr) {
assert(allocator!=nil);
assert(old_memory!=nil);
header_adr := (rawptr)((uintptr)(old_memory)-size_of(Alloc_Header));
header := (^Alloc_Header)(header_adr);
assert(header.magic==Alloc_Header_Magic);
assert(allocator.curr_alloc_count>0);
assert(allocator.curr_mem_alloc>=u64(header.size));
allocator.curr_alloc_count -= 1;
allocator.curr_mem_alloc -= u64(header.size);
if header.prev==nil {
assert(allocator.head==header);
allocator.head = header.next;
} else {
header.prev.next = header.next;
}
if header.next!=nil {
header.next.prev = header.prev;
}
os.heap_free(header_adr);
}
allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
using mem.Allocator_Mode;
assert(allocator_data!=nil);
allocator := (^Allocator)(allocator_data);
assert(allocator.magic==Allocator_Magic);
assert(allocator.thread_id==context.thread_id);
switch mode {
case Alloc:
return _internal_alloc(allocator, size, loc);
case Free:
_internal_free(allocator, old_memory);
return nil;
case Free_All:
// NOTE(bill): Does nothing
case Resize:
if old_memory == nil {
return _internal_alloc(allocator, size, loc);
} else if size == 0 {
_internal_free(allocator, old_memory);
return nil;
} else {
ptr := _internal_alloc(allocator, size, loc);
mem.copy(ptr, old_memory, old_size );
_internal_free(allocator, old_memory);
return ptr;
}
}
return nil;
}
allocator_get :: proc ( allocator: ^Allocator ) -> mem.Allocator {
allocator.magic = Allocator_Magic;
allocator.thread_id = context.thread_id;
return mem.Allocator{
procedure = allocator_proc,
data = allocator,
};
}
print_leaks :: proc(allocator: ^Allocator) {
fmt.println("=== Allocator Stats === ");
fmt.printf(" [current] alloc count: %v mem: %v kb\n", allocator.curr_alloc_count, f64(allocator.curr_mem_alloc)/1024.0 );
fmt.printf(" [peak] alloc count: %v mem: %v kb\n", allocator.peak_alloc_count, f64(allocator.peak_alloc_count)/1024.0 );
fmt.printf(" [total] alloc count: %v\n", allocator.total_alloc_count );
assert(allocator!=nil);
alloc_header := allocator.head;
if alloc_header!= nil {
fmt.println("!!! Leaks detected !!!");
} else {
fmt.println("No leak detected");
}
for alloc_header!=nil {
fmt.printf("\t size: %v %v\n", alloc_header.size, alloc_header.location );
alloc_header = alloc_header.next;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment