mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 20:58:15 +00:00
Merge branch 'master' into file-tags-without-comments
This commit is contained in:
@@ -4,50 +4,85 @@ package mem
|
||||
import "base:runtime"
|
||||
import "core:sync"
|
||||
|
||||
/*
|
||||
Allocation entry for the tracking allocator.
|
||||
|
||||
This structure stores the data related to an allocation.
|
||||
*/
|
||||
Tracking_Allocator_Entry :: struct {
|
||||
memory: rawptr,
|
||||
size: int,
|
||||
// Pointer to an allocated region.
|
||||
memory: rawptr,
|
||||
// Size of the allocated memory region.
|
||||
size: int,
|
||||
// Requested alignment.
|
||||
alignment: int,
|
||||
mode: Allocator_Mode,
|
||||
err: Allocator_Error,
|
||||
// Mode of the operation.
|
||||
mode: Allocator_Mode,
|
||||
// Error.
|
||||
err: Allocator_Error,
|
||||
// Location of the allocation.
|
||||
location: runtime.Source_Code_Location,
|
||||
}
|
||||
|
||||
/*
|
||||
Bad free entry for a tracking allocator.
|
||||
*/
|
||||
Tracking_Allocator_Bad_Free_Entry :: struct {
|
||||
memory: rawptr,
|
||||
// Pointer, on which free operation was called.
|
||||
memory: rawptr,
|
||||
// The source location of where the operation was called.
|
||||
location: runtime.Source_Code_Location,
|
||||
}
|
||||
Tracking_Allocator :: struct {
|
||||
backing: Allocator,
|
||||
allocation_map: map[rawptr]Tracking_Allocator_Entry,
|
||||
bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry,
|
||||
mutex: sync.Mutex,
|
||||
clear_on_free_all: bool,
|
||||
|
||||
total_memory_allocated: i64,
|
||||
total_allocation_count: i64,
|
||||
total_memory_freed: i64,
|
||||
total_free_count: i64,
|
||||
peak_memory_allocated: i64,
|
||||
/*
|
||||
Tracking allocator data.
|
||||
*/
|
||||
Tracking_Allocator :: struct {
|
||||
backing: Allocator,
|
||||
allocation_map: map[rawptr]Tracking_Allocator_Entry,
|
||||
bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry,
|
||||
mutex: sync.Mutex,
|
||||
clear_on_free_all: bool,
|
||||
total_memory_allocated: i64,
|
||||
total_allocation_count: i64,
|
||||
total_memory_freed: i64,
|
||||
total_free_count: i64,
|
||||
peak_memory_allocated: i64,
|
||||
current_memory_allocated: i64,
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the tracking allocator.
|
||||
|
||||
This procedure initializes the tracking allocator `t` with a backing allocator
|
||||
specified with `backing_allocator`. The `internals_allocator` will used to
|
||||
allocate the tracked data.
|
||||
*/
|
||||
tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Allocator, internals_allocator := context.allocator) {
|
||||
t.backing = backing_allocator
|
||||
t.allocation_map.allocator = internals_allocator
|
||||
t.bad_free_array.allocator = internals_allocator
|
||||
|
||||
if .Free_All in query_features(t.backing) {
|
||||
t.clear_on_free_all = true
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Destroy the tracking allocator.
|
||||
*/
|
||||
tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
|
||||
delete(t.allocation_map)
|
||||
delete(t.bad_free_array)
|
||||
}
|
||||
|
||||
/*
|
||||
Clear the tracking allocator.
|
||||
|
||||
// Clear only the current allocation data while keeping the totals intact.
|
||||
This procedure clears the tracked data from a tracking allocator.
|
||||
|
||||
**Note**: This procedure clears only the current allocation data while keeping
|
||||
the totals intact.
|
||||
*/
|
||||
tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
|
||||
sync.mutex_lock(&t.mutex)
|
||||
clear(&t.allocation_map)
|
||||
@@ -56,7 +91,11 @@ tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
|
||||
sync.mutex_unlock(&t.mutex)
|
||||
}
|
||||
|
||||
// Reset all of a Tracking Allocator's allocation data back to zero.
|
||||
/*
|
||||
Reset the tracking allocator.
|
||||
|
||||
Reset all of a Tracking Allocator's allocation data back to zero.
|
||||
*/
|
||||
tracking_allocator_reset :: proc(t: ^Tracking_Allocator) {
|
||||
sync.mutex_lock(&t.mutex)
|
||||
clear(&t.allocation_map)
|
||||
@@ -70,6 +109,39 @@ tracking_allocator_reset :: proc(t: ^Tracking_Allocator) {
|
||||
sync.mutex_unlock(&t.mutex)
|
||||
}
|
||||
|
||||
/*
|
||||
Tracking allocator.
|
||||
|
||||
The tracking allocator is an allocator wrapper that tracks memory allocations.
|
||||
This allocator stores all the allocations in a map. Whenever a pointer that's
|
||||
not inside of the map is freed, the `bad_free_array` entry is added.
|
||||
|
||||
An example of how to use the `Tracking_Allocator` to track subsequent allocations
|
||||
in your program and report leaks and bad frees:
|
||||
|
||||
Example:
|
||||
|
||||
package foo
|
||||
|
||||
import "core:mem"
|
||||
import "core:fmt"
|
||||
|
||||
main :: proc() {
|
||||
track: mem.Tracking_Allocator
|
||||
mem.tracking_allocator_init(&track, context.allocator)
|
||||
defer mem.tracking_allocator_destroy(&track)
|
||||
context.allocator = mem.tracking_allocator(&track)
|
||||
|
||||
do_stuff()
|
||||
|
||||
for _, leak in track.allocation_map {
|
||||
fmt.printf("%v leaked %m\n", leak.location, leak.size)
|
||||
}
|
||||
for bad_free in track.bad_free_array {
|
||||
fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)
|
||||
}
|
||||
}
|
||||
*/
|
||||
@(require_results)
|
||||
tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
||||
return Allocator{
|
||||
@@ -78,9 +150,14 @@ tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
|
||||
}
|
||||
}
|
||||
|
||||
tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
|
||||
tracking_allocator_proc :: proc(
|
||||
allocator_data: rawptr,
|
||||
mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr,
|
||||
old_size: int,
|
||||
loc := #caller_location,
|
||||
) -> (result: []byte, err: Allocator_Error) {
|
||||
track_alloc :: proc(data: ^Tracking_Allocator, entry: ^Tracking_Allocator_Entry) {
|
||||
data.total_memory_allocated += i64(entry.size)
|
||||
data.total_allocation_count += 1
|
||||
|
||||
Reference in New Issue
Block a user