From c405c47e6cf58bee24456e051a40a6bf897d11e3 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 20 Jun 2024 15:36:47 -0400 Subject: [PATCH] mem tracker updates --- code/grime/hashmap_chained.odin | 6 ++++-- code/grime/memory_tracker.odin | 19 +++++++++--------- code/grime/pool_allocator.odin | 20 +++++++++++++------ code/grime/slab_allocator.odin | 32 ++++++++++++++++++++----------- code/grime/virtual_arena.odin | 22 ++++++++++----------- code/host/host.odin | 3 ++- code/sectr/engine/client_api.odin | 2 +- 7 files changed, 63 insertions(+), 41 deletions(-) diff --git a/code/grime/hashmap_chained.odin b/code/grime/hashmap_chained.odin index 2bab34b..c1f1835 100644 --- a/code/grime/hashmap_chained.odin +++ b/code/grime/hashmap_chained.odin @@ -57,7 +57,8 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_ pool_bucket_cap : uint = 1 * Kilo, pool_bucket_reserve_num : uint = 0, pool_alignment : uint = mem.DEFAULT_ALIGNMENT, - dbg_name : string = "" + dbg_name : string = "", + enable_mem_tracking : b32 = false, ) -> (table : HMapChained(Type), error : AllocatorError) { header_size := size_of(HMapChainedHeader(Type)) @@ -75,7 +76,8 @@ hmap_chained_init :: proc( $HMapChainedType : typeid/HMapChained($Type), lookup_ bucket_reserve_num = pool_bucket_reserve_num, alignment = pool_alignment, allocator = allocator, - dbg_name = str_intern(str_fmt("%v: pool", dbg_name)).str + dbg_name = str_intern(str_fmt("%v: pool", dbg_name)).str, + enable_mem_tracking = enable_mem_tracking, ) data := transmute([^] ^HMapChainedSlot(Type)) (transmute( [^]HMapChainedHeader(Type)) table.header)[1:] table.lookup = slice_ptr( data, int(lookup_capacity) ) diff --git a/code/grime/memory_tracker.odin b/code/grime/memory_tracker.odin index a73674f..ee57694 100644 --- a/code/grime/memory_tracker.odin +++ b/code/grime/memory_tracker.odin @@ -13,11 +13,12 @@ MemoryTrackerEntry :: struct { } MemoryTracker :: struct { + parent : ^MemoryTracker, name : string, entries : Array(MemoryTrackerEntry), } -Track_Memory :: false +Track_Memory :: true memtracker_clear :: proc ( tracker : MemoryTracker ) { when ! Track_Memory { @@ -69,17 +70,17 @@ memtracker_register :: proc( tracker : ^MemoryTracker, new_entry : MemoryTracker if (entry.end < new_entry.start) { - msg := str_fmt("Memory tracker(%v) detected a collision:\nold_entry: %v\nnew_entry: %v", tracker.name, entry, new_entry) + msg := str_fmt("Detected a collision:\nold_entry: %v -> %v\nnew_entry: %v -> %v | %v", entry.start, entry.end, new_entry.start, new_entry.end, tracker.name ) ensure( false, msg ) memtracker_dump_entries(tracker ^) } array_append_at( & tracker.entries, new_entry, idx ) - logf("%v : Registered: %v", tracker.name, new_entry) + logf("Registered: %v -> %v | %v", new_entry.start, new_entry.end, tracker.name) return } array_append( & tracker.entries, new_entry ) - logf("%v : Registered: %v", tracker.name, new_entry) + logf("Registered: %v -> %v | %v", new_entry.start, new_entry.end, tracker.name ) } memtracker_register_auto_name :: proc( tracker : ^MemoryTracker, start, end : rawptr ) @@ -117,17 +118,17 @@ memtracker_unregister :: proc( tracker : MemoryTracker, to_remove : MemoryTracke entry := & entries[idx] if entry.start == to_remove.start { if (entry.end == to_remove.end || to_remove.end == nil) { - logf("%v: Unregistered: %v", tracker.name, to_remove); + logf("Unregistered: %v -> %v | %v", to_remove.start, to_remove.end, tracker.name ); array_remove_at(tracker.entries, idx) return } - ensure(false, str_fmt("%v: Found an entry with the same start address but end address was different:\nentry : %v\nto_remove: %v", tracker.name, entry, to_remove)) + ensure(false, str_fmt("Found an entry with the same start address but end address was different:\nentry : %v -> %v\nto_remove: %v -> %v | %v", entry.start, entry.end, to_remove.start, to_remove.end, tracker.name )) memtracker_dump_entries(tracker) } } - ensure(false, str_fmt("%v: Attempted to unregister an entry that was not tracked: %v", tracker.name, to_remove)) + ensure(false, str_fmt("Attempted to unregister an entry that was not tracked: %v -> %v | %v", to_remove.start, to_remove.end, tracker.name)) memtracker_dump_entries(tracker) } @@ -150,7 +151,7 @@ memtracker_check_for_collisions :: proc ( tracker : MemoryTracker ) collided := left.start > right.start || left.end > right.end if collided { - msg := str_fmt("%v: Memory tracker detected a collision:\nleft: %v\nright: %v", tracker.name, left, right) + msg := str_fmt("Memory tracker detected a collision:\nleft: %v\nright: %v | %v", left, right, tracker.name ) memtracker_dump_entries(tracker) } } @@ -165,6 +166,6 @@ memtracker_dump_entries :: proc( tracker : MemoryTracker ) log( "Dumping Memory Tracker:") for idx in 0 ..< tracker.entries.num { entry := & tracker.entries.data[idx] - logf("%v", entry) + logf("%v -> %v", entry.start, entry.end) } } diff --git a/code/grime/pool_allocator.odin b/code/grime/pool_allocator.odin index 9e937a2..c46d1b1 100644 --- a/code/grime/pool_allocator.odin +++ b/code/grime/pool_allocator.odin @@ -25,7 +25,8 @@ Pool :: struct { PoolHeader :: struct { backing : Allocator, dbg_name : string, - tracker : MemoryTracker, + tracker : MemoryTracker, + // bucket_tracker : MemoryTracker, zero_bucket : b32, block_size : uint, @@ -57,6 +58,7 @@ pool_init :: proc ( alignment : uint = mem.DEFAULT_ALIGNMENT, allocator : Allocator = context.allocator, dbg_name : string = "", + enable_mem_tracking : b32 = false, ) -> ( pool : Pool, alloc_error : AllocatorError ) { header_size := align_forward_int( size_of(PoolHeader), int(alignment) ) @@ -76,8 +78,9 @@ pool_init :: proc ( pool.bucket_capacity = bucket_capacity pool.alignment = alignment - when ODIN_DEBUG { + if Track_Memory && enable_mem_tracking { memtracker_init( & pool.tracker, allocator, Kilobyte * 96, dbg_name ) + // memtracker_init( & pool.bucket_tracker, allocator, Kilobyte * 96, dbg_name ) } if bucket_reserve_num > 0 { @@ -104,8 +107,9 @@ pool_destroy :: proc ( using self : Pool ) free( self.header, backing ) - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_clear( self.tracker ) + // memtracker_clear( self.bucket_tracker ) } } @@ -133,6 +137,10 @@ pool_allocate_buckets :: proc( pool : Pool, num_buckets : uint ) -> AllocatorErr } pool_validate( pool ) + // if Track_Memory && pool.tracker.entries.header != nil { + // memtracker_register_auto_name_slice( & pool.bucket_tracker, bucket_memory) + // } + // log(str_fmt_tmp("Bucket memory size: %d bytes, without header: %d", len(bucket_memory), len(bucket_memory) - int(header_size))) if alloc_error != .None { @@ -195,7 +203,7 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo slice.zero(block) } - when ODIN_DEBUG { + if Track_Memory && pool.tracker.entries.header != nil { memtracker_register_auto_name_slice( & pool.tracker, block) } return @@ -258,7 +266,7 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo // log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", block_ptr, cast(rawptr) (uintptr(block_ptr) + uintptr(pool.block_size)))) } - when ODIN_DEBUG { + if Track_Memory && pool.tracker.entries.header != nil { memtracker_register_auto_name_slice( & pool.tracker, block) } return @@ -289,7 +297,7 @@ pool_release :: proc( self : Pool, block : []byte, loc := #caller_location ) start := new_free_block end := transmute(rawptr) (uintptr(new_free_block) + uintptr(self.block_size) - 1) - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_unregister( self.tracker, { start, end } ) } } diff --git a/code/grime/slab_allocator.odin b/code/grime/slab_allocator.odin index 27623c8..7d6de40 100644 --- a/code/grime/slab_allocator.odin +++ b/code/grime/slab_allocator.odin @@ -27,6 +27,7 @@ package grime import "base:runtime" import "core:mem" import "core:slice" +import "core:strings" SlabSizeClass :: struct { bucket_capacity : uint, @@ -55,7 +56,12 @@ slab_allocator :: proc( slab : Slab ) -> ( allocator : Allocator ) { return } -slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, allocator : Allocator = context.allocator, dbg_name : string = "", should_zero_buckets : b32 = false ) -> ( slab : Slab, alloc_error : AllocatorError ) +slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, + allocator : Allocator = context.allocator, + dbg_name : string = "", + should_zero_buckets : b32 = false, + enable_mem_tracking : b32 = false, +) -> ( slab : Slab, alloc_error : AllocatorError ) { header_size :: size_of( SlabHeader ) @@ -66,10 +72,10 @@ slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, allocato slab.header = cast( ^SlabHeader) raw_mem slab.backing = allocator slab.dbg_name = dbg_name - when ODIN_DEBUG { + if Track_Memory && enable_mem_tracking { memtracker_init( & slab.tracker, allocator, Kilobyte * 256, dbg_name ) } - alloc_error = slab_init_pools( slab, policy, bucket_reserve_num, should_zero_buckets ) + alloc_error = slab_init_pools( slab, policy, bucket_reserve_num, should_zero_buckets ) return } @@ -80,8 +86,12 @@ slab_init_pools :: proc ( using self : Slab, policy : ^SlabPolicy, bucket_reserv for id in 0 ..< policy.idx { using size_class := policy.items[id] - pool_dbg_name := str_fmt("%v pool[%v]", dbg_name, block_size, allocator = backing) - pool, alloc_error := pool_init( should_zero_buckets, block_size, bucket_capacity, bucket_reserve_num, block_alignment, backing, pool_dbg_name ) + name_temp := str_fmt_tmp("%v pool[%v]", dbg_name, block_size) + pool_dbg_name, error := strings.clone( name_temp, allocator = backing ) + pool, alloc_error := pool_init( should_zero_buckets, block_size, bucket_capacity, bucket_reserve_num, block_alignment, backing, + pool_dbg_name, + enable_mem_tracking = Track_Memory && tracker.entries.header != nil + ) if alloc_error != .None do return alloc_error push( & self.pools, pool ) @@ -107,7 +117,7 @@ slab_destroy :: proc( using self : Slab ) } free( self.header, backing ) - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_clear(tracker) } } @@ -148,7 +158,7 @@ slab_alloc :: proc( self : Slab, slice.zero(data) } - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_register_auto_name( & self.tracker, raw_data(block), & block[ len(block) - 1 ] ) } return @@ -165,7 +175,7 @@ slab_free :: proc( using self : Slab, data : []byte, loc := #caller_location ) start := raw_data(data) end := ptr_offset(start, pool.block_size - 1) - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_unregister( self.tracker, { start, end } ) } @@ -255,13 +265,13 @@ slab_resize :: proc( using self : Slab, start := raw_data( data ) end := rawptr(uintptr(start) + uintptr(pool_old.block_size) - 1) - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_unregister( self.tracker, { start, end } ) } } new_data = new_block[ :new_size] - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_register_auto_name( & self.tracker, raw_data(new_block), & new_block[ len(new_block) - 1 ] ) } return @@ -273,7 +283,7 @@ slab_reset :: proc( slab : Slab ) pool := slab.pools.items[id] pool_reset( pool ) } - when ODIN_DEBUG { + when Track_Memory { memtracker_clear(slab.tracker) } } diff --git a/code/grime/virtual_arena.odin b/code/grime/virtual_arena.odin index 6c81864..a734b8d 100644 --- a/code/grime/virtual_arena.odin +++ b/code/grime/virtual_arena.odin @@ -29,7 +29,7 @@ VArena :: struct { dbg_name : string, commit_used : uint, growth_policy : VArena_GrowthPolicyProc, - allow_any_reize : b32, + allow_any_resize : b32, mutex : sync.Mutex, } @@ -61,7 +61,7 @@ varena_allocator :: proc( arena : ^VArena ) -> ( allocator : Allocator ) { // Default growth_policy is nil varena_init :: proc( base_address : uintptr, to_reserve, to_commit : uint, - growth_policy : VArena_GrowthPolicyProc, allow_any_reize : b32 = false, dbg_name : string + growth_policy : VArena_GrowthPolicyProc, allow_any_resize : b32 = false, dbg_name : string, enable_mem_tracking : b32 = false, ) -> ( arena : VArena, alloc_error : AllocatorError) { page_size := uint(virtual_get_page_size()) @@ -86,9 +86,9 @@ varena_init :: proc( base_address : uintptr, to_reserve, to_commit : uint, else { arena.growth_policy = growth_policy } - arena.allow_any_reize = allow_any_reize + arena.allow_any_resize = allow_any_resize - when ODIN_DEBUG { + if Track_Memory && enable_mem_tracking { memtracker_init( & arena.tracker, runtime.heap_allocator(), Kilobyte * 128, dbg_name ) } return @@ -165,7 +165,7 @@ varena_alloc :: proc( using self : ^VArena, mem_zero( data_ptr, int(requested_size) ) } - when ODIN_DEBUG { + if Track_Memory && self.tracker.entries.header != nil { memtracker_register_auto_name( & tracker, & data[0], & data[len(data) - 1] ) } return @@ -176,7 +176,7 @@ varena_free_all :: proc( using self : ^VArena ) sync.mutex_guard( & mutex ) commit_used = 0 - when ODIN_DEBUG && Track_Memory { + if Track_Memory && self.tracker.entries.header != nil { array_clear(tracker.entries) } } @@ -251,13 +251,13 @@ varena_allocator_proc :: proc( } } - verify( old_memory_offset == current_offset || arena.allow_any_reize, + verify( old_memory_offset == current_offset || arena.allow_any_resize, "Cannot resize existing allocation in vitual arena to a larger size unless it was the last allocated" ) log_backing : [Kilobyte * 16]byte backing_slice := byte_slice( & log_backing[0], len(log_backing)) - if old_memory_offset != current_offset && arena.allow_any_reize + if old_memory_offset != current_offset && arena.allow_any_resize { // Give it new memory and copy the old over. Old memory is unrecoverable until clear. new_region : []byte @@ -266,7 +266,7 @@ varena_allocator_proc :: proc( ensure(false, "Failed to grab new region") data = byte_slice( old_memory, old_size ) - when ODIN_DEBUG { + if Track_Memory && arena.tracker.entries.header != nil { memtracker_register_auto_name( & arena.tracker, & data[0], & data[len(data) - 1] ) } return @@ -276,7 +276,7 @@ varena_allocator_proc :: proc( data = new_region // log( str_fmt_tmp("varena resize (new): old: %p %v new: %p %v", old_memory, old_size, (& data[0]), size)) - when ODIN_DEBUG { + when Track_Memory { memtracker_register_auto_name( & arena.tracker, & data[0], & data[len(data) - 1] ) } return @@ -293,7 +293,7 @@ varena_allocator_proc :: proc( data = byte_slice( old_memory, size ) // log( str_fmt_tmp("varena resize (expanded): old: %p %v new: %p %v", old_memory, old_size, (& data[0]), size)) - when ODIN_DEBUG { + if Track_Memory && arena.tracker.entries.header != nil { memtracker_register_auto_name( & arena.tracker, & data[0], & data[len(data) - 1] ) } return diff --git a/code/host/host.odin b/code/host/host.odin index 9eab156..73e6480 100644 --- a/code/host/host.odin +++ b/code/host/host.odin @@ -129,7 +129,8 @@ setup_memory :: proc( profiler : ^SpallProfiler ) -> ClientMemory sectr.Memory_Commit_Initial_Persistent, growth_policy = nil, allow_any_resize = false, - dbg_name = "persistent" ) + dbg_name = "persistent", + enable_mem_tracking = true ) verify( alloc_error == .None, "Failed to allocate persistent virtual arena for the sectr module") frame, alloc_error = varena_init( diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index dd71511..64f2e79 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -92,7 +92,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // push( policy_ptr, SlabSizeClass { 512 * Megabyte, 512 * Megabyte, alignment }) alloc_error : AllocatorError - persistent_slab, alloc_error = slab_init( policy_ptr, allocator = persistent_allocator(), dbg_name = Persistent_Slab_DBG_Name ) + persistent_slab, alloc_error = slab_init( policy_ptr, allocator = persistent_allocator(), dbg_name = Persistent_Slab_DBG_Name, enable_mem_tracking = true ) verify( alloc_error == .None, "Failed to allocate the persistent slab" ) transient_slab, alloc_error = slab_init( & default_slab_policy, allocator = transient_allocator(), dbg_name = Transient_Slab_DBG_Name )