Created
December 10, 2018 21:31
-
-
Save benoitjacquier/62299cb6ab923641c52d71ae8efa06eb to your computer and use it in GitHub Desktop.
allocator with leaktracker using odin-lang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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