More fixes & performance improvements

Still havent figured out the realloc issue with virtual arenas... But the fixes the slab perforamnce mitigate it at least.
This commit is contained in:
Edward R. Gonzalez 2024-03-12 02:32:16 -04:00
parent 8b8c4948ad
commit b4c6fd1866
11 changed files with 58 additions and 64 deletions

View File

@ -249,8 +249,8 @@ reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem,
// Thankfully persistent dynamic allocations are rare, and thus we know exactly which ones they are.
font_provider_data := & state.font_provider_data
font_provider_data.font_cache.hashes.allocator = persistent_slab_allocator()
font_provider_data.font_cache.entries.allocator = persistent_slab_allocator()
font_provider_data.font_cache.hashes.backing = persistent_slab_allocator()
font_provider_data.font_cache.entries.backing = persistent_slab_allocator()
ui_reload( & get_state().project.workspace.ui, cache_allocator = persistent_slab_allocator() )

View File

@ -37,6 +37,7 @@ import "core:mem"
AllocatorModeSet :: mem.Allocator_Mode_Set
alloc :: mem.alloc
alloc_bytes :: mem.alloc_bytes
alloc_bytes_non_zeroed :: mem.alloc_bytes_non_zeroed
Arena :: mem.Arena
arena_allocator :: mem.arena_allocator
arena_init :: mem.arena_init
@ -46,6 +47,7 @@ import "core:mem"
is_power_of_two_uintptr :: mem.is_power_of_two
ptr_offset :: mem.ptr_offset
resize :: mem.resize
reisze_non_zeroed :: mem.default_resize_bytes_align_non_zeroed
slice_ptr :: mem.slice_ptr
TrackingAllocator :: mem.Tracking_Allocator
tracking_allocator :: mem.tracking_allocator

View File

@ -8,14 +8,14 @@ import "core:mem"
import "core:slice"
// Array :: struct ( $ Type : typeid ) {
// allocator : Allocator,
// bakcing : Allocator,
// capacity : u64,
// num : u64,
// data : [^]Type,
// }
ArrayHeader :: struct ( $ Type : typeid ) {
allocator : Allocator,
backing : Allocator,
capacity : u64,
num : u64,
data : [^]Type,
@ -62,7 +62,7 @@ array_init_reserve :: proc
if alloc_error != AllocatorError.None do return
result.header = cast( ^ArrayHeader(Type)) raw_mem;
result.allocator = allocator
result.backing = allocator
result.capacity = capacity
result.data = cast( [^]Type ) (cast( [^]ArrayHeader(Type)) result.header)[ 1:]
return
@ -201,13 +201,13 @@ array_fill :: proc( using self : Array( $ Type ), begin, end : u64, value : Type
}
array_free :: proc( using self : Array( $ Type ) ) {
free( data, allocator )
free( data, backing )
self.data = nil
}
array_grow :: proc( using self : ^Array( $ Type ), min_capacity : u64 ) -> AllocatorError
{
profile(#procedure)
// profile(#procedure)
new_capacity := array_grow_formula( capacity )
if new_capacity < min_capacity {
@ -269,13 +269,19 @@ array_set_capacity :: proc( self : ^Array( $ Type ), new_capacity : u64 ) -> All
new_size := header_size + cast(int) new_capacity * size_of(Type)
old_size := header_size + cast(int) self.capacity * size_of(Type)
new_mem, result_code := resize( self.header, old_size, new_size, allocator = self.allocator )
// new_mem, result_code := resize( self.header, old_size, new_size, allocator = self.backing )
new_mem, result_code := reisze_non_zeroed( byte_slice( self.header, old_size), new_size, mem.DEFAULT_ALIGNMENT, allocator = self.backing )
if result_code != AllocatorError.None {
ensure( false, "Failed to allocate for new array capacity" )
return result_code
}
if new_mem == nil {
ensure(false, "new_mem is nil but no allocation error")
return result_code
}
self.header = cast( ^ArrayHeader(Type)) new_mem;
self.header = cast( ^ArrayHeader(Type)) raw_data(new_mem);
self.data = cast( [^]Type ) (cast( [^]ArrayHeader(Type)) self.header)[ 1:]
self.capacity = new_capacity
self.num = self.num

View File

@ -119,7 +119,7 @@ zpl_hmap_rehash :: proc( ht : ^ HMapZPL( $ Type ), new_num : u64 ) -> AllocatorE
ensure( false, "ZPL HMAP IS REHASHING" )
last_added_index : i64
new_ht, init_result := zpl_hmap_init_reserve( Type, ht.hashes.allocator, new_num )
new_ht, init_result := zpl_hmap_init_reserve( Type, ht.hashes.backing, new_num )
if init_result != AllocatorError.None {
ensure( false, "New zpl_hmap failed to allocate" )
return init_result

View File

@ -43,12 +43,6 @@ Pool_FreeBlock :: struct {
Pool_Check_Release_Object_Validity :: true
pool_allocator :: proc ( using self : Pool ) -> (allocator : Allocator) {
allocator.procedure = pool_allocator_proc
allocator.data = self.header
return
}
pool_init :: proc (
block_size : uint,
bucket_capacity : uint,
@ -98,12 +92,12 @@ pool_allocate_buckets :: proc( using self : Pool, num_buckets : uint ) -> Alloca
header_size := cast(uint) align_forward_int( size_of(PoolBucket), int(alignment))
to_allocate := cast(int) (header_size + bucket_capacity * num_buckets)
bucket_memory, alloc_error := alloc( to_allocate, int(alignment), backing )
bucket_memory, alloc_error := alloc_bytes_non_zeroed( to_allocate, int(alignment), backing )
if alloc_error != .None {
return alloc_error
}
next_bucket_ptr := cast( [^]byte) bucket_memory
next_bucket_ptr := cast( [^]byte) raw_data(bucket_memory)
for index in 0 ..< num_buckets
{
bucket := cast( ^PoolBucket) next_bucket_ptr
@ -151,6 +145,7 @@ pool_grab :: proc( using pool : Pool ) -> ( block : []byte, alloc_error : Alloca
{
alloc_error = pool_allocate_buckets( pool, 1 )
if alloc_error != .None {
ensure(false, "Failed to allocate bucket")
return
}
pool.current_bucket = bucket_list.first
@ -175,6 +170,7 @@ pool_grab :: proc( using pool : Pool ) -> ( block : []byte, alloc_error : Alloca
{
alloc_error := pool_allocate_buckets( pool, 1 )
if alloc_error != .None {
ensure(false, "Failed to allocate bucket")
return
}
pool.current_bucket = pool.current_bucket.next
@ -243,33 +239,3 @@ pool_validate_ownership :: proc( using self : Pool, block : [] byte ) -> b32
return within_bucket
}
// This interface should really not be used for a pool allocator... But fk it its here.
// TODO(Ed): Implement this eventaully..
pool_allocator_proc :: proc(
allocator_data : rawptr,
mode : AllocatorMode,
size : int,
alignment : int,
old_memory : rawptr,
old_size : int,
loc := #caller_location
) -> ([]byte, AllocatorError)
{
switch mode
{
case .Alloc, .Alloc_Non_Zeroed:
fallthrough
case .Free:
fallthrough
case .Free_All:
fallthrough
case .Resize, .Resize_Non_Zeroed:
fallthrough
case .Query_Features:
fallthrough
case .Query_Info:
fallthrough
}
return nil, AllocatorError.Mode_Not_Implemented
}

View File

@ -75,6 +75,7 @@ slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, allocato
slab_init_pools :: proc ( using self : Slab, bucket_reserve_num : uint = 0 ) -> AllocatorError
{
profile(#procedure)
for id in 0 ..< policy.idx {
using size_class := policy.items[id]

View File

@ -75,7 +75,7 @@ str_intern :: proc(
{
length := len(content)
// str_mem, alloc_error := alloc( length, mem.DEFAULT_ALIGNMENT )
str_mem, alloc_error := slab_alloc( cache.slab, uint(length), uint(mem.DEFAULT_ALIGNMENT) )
str_mem, alloc_error := slab_alloc( cache.slab, uint(length), uint(mem.DEFAULT_ALIGNMENT), zero_memory = false )
verify( alloc_error == .None, "String cache had a backing allocator error" )
// copy_non_overlapping( str_mem, raw_data(content), length )

View File

@ -100,13 +100,16 @@ varena_alloc :: proc( using self : ^VArena,
requested_size := size
if requested_size == 0 {
ensure(false, "Requested 0 size")
return nil, .Invalid_Argument
}
// ensure( requested_size > page_size, "Requested less than a page size, going to allocate a page size")
// requested_size = max(requested_size, page_size)
sync.mutex_guard( & mutex )
alignment_offset := uint(0)
current_offset := cast(uintptr) reserve_start[ commit_used:]
current_offset := uintptr(self.reserve_start) + uintptr(commit_used)
mask := uintptr(alignment - 1)
if current_offset & mask != 0 {
@ -140,10 +143,9 @@ varena_alloc :: proc( using self : ^VArena,
}
}
aligned_start := uintptr(self.commit_used + alignment_offset)
data_ptr := rawptr(uintptr( reserve_start ) + aligned_start)
data_ptr := rawptr(current_offset + uintptr(alignment_offset))
data = byte_slice( data_ptr, int(requested_size) )
commit_used += size_to_allocate
self.commit_used += size_to_allocate
alloc_error = .None
if zero_memory {
@ -182,6 +184,8 @@ varena_allocator_proc :: proc(
alignment := uint(alignment)
old_size := uint(old_size)
page_size := uint(virtual_get_page_size())
switch mode
{
case .Alloc, .Alloc_Non_Zeroed:
@ -195,31 +199,43 @@ varena_allocator_proc :: proc(
case .Resize, .Resize_Non_Zeroed:
if old_memory == nil {
ensure(false, "Resizing without old_memory?")
return varena_alloc( arena, size, alignment, (mode != .Resize_Non_Zeroed), location )
}
if size == old_size {
ensure(false, "Requested resize when none needed")
data = byte_slice( old_memory, old_size )
return
}
alignment_offset := uintptr(old_memory) & uintptr(alignment - 1)
if alignment_offset == 0 && size < old_size {
ensure(false, "Requested a shrink from a virtual arena")
data = byte_slice( old_memory, size )
return
}
old_memory_offset := uintptr(old_memory) + uintptr(old_size)
current_offset := uintptr(arena.reserve_start) + uintptr(arena.commit_used)
// if old_size < page_size {
// // We're dealing with an allocation that requested less than the minimum allocated on vmem.
// // Provide them more of their actual memory
// data = byte_slice( old_memory, size )
// return
// }
verify( old_memory_offset == current_offset || arena.allow_any_reize,
"Cannot resize existing allocation in vitual arena to a larger size unless it was the last allocated" )
if old_memory_offset == current_offset && arena.allow_any_reize
if old_memory_offset != current_offset && arena.allow_any_reize
{
// Give it new memory and copy the old over. Old memory is unrecoverable until clear.
new_region : []byte
new_region, alloc_error = varena_alloc( arena, size, alignment, (mode != .Resize_Non_Zeroed), location )
if new_region == nil || alloc_error != .None {
ensure(false, "Failed to grab new region")
data = byte_slice( old_memory, old_size )
return
}
@ -232,6 +248,7 @@ varena_allocator_proc :: proc(
new_region : []byte
new_region, alloc_error = varena_alloc( arena, size - old_size, alignment, (mode != .Resize_Non_Zeroed), location )
if new_region == nil || alloc_error != .None {
ensure(false, "Failed to grab new region")
data = byte_slice( old_memory, old_size )
return
}

View File

@ -252,7 +252,7 @@ pws_parser_parse :: proc( text : string, allocator : Allocator ) -> ( PWS_ParseR
nodes, alloc_error = array_init_reserve( PWS_AST, allocator, 8 )
verify( alloc_error == nil, "Allocation failure creating nodes array")
lines, alloc_error = array_init_reserve( ^PWS_AST, allocator, 8 )
parser.lines, alloc_error = array_init_reserve( ^PWS_AST, allocator, 8 )
verify( alloc_error == nil, "Allocation failure creating line array")
//region Helper procs
@ -301,12 +301,11 @@ pws_parser_parse :: proc( text : string, allocator : Allocator ) -> ( PWS_ParseR
type = .Visible
case .New_Line:
{
eat_line()
alloc_error = array_append( & lines, prev_line )
alloc_error = array_append( & parser.lines, prev_line )
verify( alloc_error == nil, "Allocation failure appending node")
}
case PWS_TokenType.End_Of_File:
}
@ -357,7 +356,7 @@ pws_parser_parse :: proc( text : string, allocator : Allocator ) -> ( PWS_ParseR
if line.first != nil {
eat_line()
alloc_error = array_append( & lines, prev_line )
alloc_error = array_append( & parser.lines, prev_line )
verify( alloc_error == nil, "Allocation failure appending node")
}

View File

@ -238,8 +238,11 @@ update :: proc( delta_time : f64 ) -> b32
test_draggable()
// test_text_box()
// Test Parenting
// Whitespace AST test
when true
when false
{
profile("Whitespace AST test")
@ -267,7 +270,7 @@ update :: proc( delta_time : f64 ) -> b32
alloc_error : AllocatorError; success : bool
// debug.lorem_content, success = os.read_entire_file( debug.path_lorem, frame_allocator() )
// debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, frame_allocator() )
// debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, frame_slab_allocator() )
// verify( alloc_error == .None, "Faield to parse due to allocation failure" )
text_space := str_intern( " " )
@ -275,7 +278,7 @@ update :: proc( delta_time : f64 ) -> b32
// index := 0
widgets : Array(UI_Widget)
widgets, alloc_error = array_init( UI_Widget, frame_allocator() )
widgets, alloc_error = array_init( UI_Widget, frame_slab_allocator() )
widgets_ptr := & widgets
label_id := 0

View File

@ -319,8 +319,8 @@ ui_reload :: proc( ui : ^ UI_State, cache_allocator : Allocator )
{
// We need to repopulate Allocator references
for cache in & ui.caches {
cache.entries.allocator = cache_allocator
cache.hashes.allocator = cache_allocator
cache.entries.backing = cache_allocator
cache.hashes.backing = cache_allocator
}
}