Trying to figure out this bug with pools...

This commit is contained in:
Edward R. Gonzalez 2024-03-20 13:34:47 -04:00
parent fb1a6063a7
commit 714d60ee34
10 changed files with 101 additions and 33 deletions

View File

@ -165,6 +165,10 @@ released :: proc {
btn_released,
}
sub :: proc {
sub_range2,
}
to_rl_rect :: proc {
range2_to_rl_rect,
}

View File

@ -60,7 +60,7 @@ array_init_reserve :: proc
raw_mem : rawptr
raw_mem, alloc_error = alloc( array_size, allocator = allocator )
log( str_fmt_tmp("array reserved: %d", header_size + int(capacity) * size_of(Type) ))
// log( str_fmt_tmp("array reserved: %d", header_size + int(capacity) * size_of(Type) ))
if alloc_error != AllocatorError.None do return
result.header = cast( ^ArrayHeader(Type)) raw_mem;

View File

@ -13,6 +13,8 @@ The pool doesn't allocate any buckets on initialization unless the user specifes
*/
package sectr
import "base:intrinsics"
import "base:runtime"
import "core:mem"
import "core:slice"
@ -29,13 +31,13 @@ PoolHeader :: struct {
free_list_head : ^Pool_FreeBlock,
current_bucket : ^PoolBucket,
bucket_list : DLL_NodeFL( PoolBucket)
bucket_list : DLL_NodeFL( PoolBucket),
}
PoolBucket :: struct {
using nodes : DLL_NodePN( PoolBucket),
next_block : uint,
blocks : [^]byte
blocks : [^]byte,
}
Pool_FreeBlock :: struct {
@ -88,21 +90,23 @@ pool_destroy :: proc ( using self : Pool )
free( self.header, backing )
}
pool_allocate_buckets :: proc( using self : Pool, num_buckets : uint ) -> AllocatorError
pool_allocate_buckets :: proc( pool : Pool, num_buckets : uint ) -> AllocatorError
{
profile(#procedure)
pool := self
if num_buckets == 0 {
return .Invalid_Argument
}
header_size := cast(uint) align_forward_int( size_of(PoolBucket), int(alignment))
bucket_size := header_size + bucket_capacity
header_size := cast(uint) align_forward_int( size_of(PoolBucket), int(pool.alignment))
bucket_size := header_size + pool.bucket_capacity
to_allocate := cast(int) (bucket_size * num_buckets)
bucket_memory, alloc_error := alloc_bytes_non_zeroed( to_allocate, int(alignment), backing )
pool_validate( pool )
bucket_memory, alloc_error := alloc_bytes_non_zeroed( to_allocate, int(pool.alignment), pool.backing )
pool_validate( pool )
if alloc_error != .None {
return alloc_error
}
verify( bucket_memory != nil, "Bucket memory is null")
next_bucket_ptr := cast( [^]byte) raw_data(bucket_memory)
for index in 0 ..< num_buckets
@ -110,15 +114,22 @@ pool_allocate_buckets :: proc( using self : Pool, num_buckets : uint ) -> Alloca
bucket := cast( ^PoolBucket) next_bucket_ptr
bucket.blocks = memory_after_header(bucket)
bucket.next_block = 0
log( str_fmt_tmp("Pool (%d) allocated bucket: %p capacity: %d", self.block_size, raw_data(bucket_memory), bucket_capacity / self.block_size))
log( str_fmt_tmp("Pool (%d) allocated bucket: %p capacity: %d",
pool.block_size,
raw_data(bucket_memory),
pool.bucket_capacity / pool.block_size
))
if bucket == cast(rawptr) uintptr(0x100017740D0) {
runtime.debug_trap()
}
if self.bucket_list.first == nil {
self.bucket_list.first = bucket
self.bucket_list.last = bucket
if pool.bucket_list.first == nil {
pool.bucket_list.first = bucket
pool.bucket_list.last = bucket
}
else {
dll_push_back( & self.bucket_list.last, bucket )
dll_push_back( & pool.bucket_list.last, bucket )
}
// log( str_fmt_tmp("Bucket List First: %p", self.bucket_list.first))
@ -130,6 +141,10 @@ pool_allocate_buckets :: proc( using self : Pool, num_buckets : uint ) -> Alloca
pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, alloc_error : AllocatorError )
{
pool := pool
if pool.current_bucket != nil {
verify( pool.current_bucket.blocks != nil, str_fmt_tmp("current_bucket was wiped %p", pool.current_bucket) )
}
// profile(#procedure)
alloc_error = .None
@ -150,6 +165,7 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo
if zero_memory {
slice.zero(block)
}
verify(false, "WE SHOULD NEVER BE HERE")
return
}
@ -172,8 +188,8 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo
next := uintptr(pool.current_bucket.blocks) + uintptr(pool.current_bucket.next_block)
end := uintptr(pool.current_bucket.blocks) + uintptr(pool.bucket_capacity)
blocks_left := end - next
if blocks_left == 0
blocks_left, overflow_signal := intrinsics.overflow_sub( end, next )
if blocks_left == 0 || overflow_signal
{
// Compiler Bug
// if current_bucket.next != nil {
@ -181,6 +197,7 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo
// current_bucket = current_bucket.next
// log( str_fmt_tmp("Bucket %p exhausted using %p", pool.current_bucket, pool.current_bucket.next))
pool.current_bucket = pool.current_bucket.next
verify( pool.current_bucket.blocks != nil, "Next's blocks are null?" )
}
else
{
@ -191,9 +208,12 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo
return
}
pool.current_bucket = pool.current_bucket.next
verify( pool.current_bucket.blocks != nil, "Next's blocks are null (Post new bucket alloc)?" )
}
}
verify( pool.current_bucket != nil, "Attempted to grab a block from a null bucket reference" )
// Compiler Bug
// block = slice_ptr( current_bucket.blocks[ current_bucket.next_block:], int(block_size) )
// self.current_bucket.next_block += block_size
@ -246,6 +266,18 @@ pool_reset :: proc( using pool : Pool )
pool.current_bucket = bucket_list.first
}
pool_validate :: proc( pool : Pool )
{
pool := pool
// Make sure all buckets don't show any indication of corruption
bucket : ^PoolBucket = pool.bucket_list.first
// Compiler bug ^^ same as pool_reset
for ; bucket != nil; bucket = bucket.next
{
verify( bucket.blocks != nil, "Found corrupted bucket" )
}
}
pool_validate_ownership :: proc( using self : Pool, block : [] byte ) -> b32
{
profile(#procedure)

View File

@ -106,7 +106,7 @@ slab_destroy :: proc( using self : Slab )
free( self.header, backing )
}
slab_alloc :: proc( using self : Slab,
slab_alloc :: proc( self : Slab,
size : uint,
alignment : uint,
zero_memory := true,
@ -116,24 +116,26 @@ slab_alloc :: proc( using self : Slab,
// profile(#procedure)
pool : Pool
id : u32 = 0
for ; id < pools.idx; id += 1 {
pool = pools.items[id]
for ; id < self.pools.idx; id += 1 {
pool = self.pools.items[id]
if pool.block_size >= size && pool.alignment >= alignment {
break
}
}
verify( id < pools.idx, "There is not a size class in the slab's policy to satisfy the requested allocation" )
verify( id < self.pools.idx, "There is not a size class in the slab's policy to satisfy the requested allocation" )
verify( pool.header != nil, "Requested alloc not supported by the slab allocator", location = loc )
block : []byte
slab_validate_pools( self )
block, alloc_error = pool_grab(pool)
if alloc_error != .None {
slab_validate_pools( self )
if block == nil || alloc_error != .None {
ensure(false, "Bad block from pool")
return nil, alloc_error
}
// log( str_fmt_tmp("%v: Retrieved block: %p %d", dbg_name, raw_data(block), len(block) ))
log( str_fmt_tmp("%v: Retrieved block: %p %d", self.dbg_name, raw_data(block), len(block) ))
data = byte_slice(raw_data(block), size)
if zero_memory {
@ -196,7 +198,9 @@ slab_resize :: proc( using self : Slab,
if zero_memory && new_size > old_size {
to_zero := byte_slice( new_data_ptr, int(new_size - old_size) )
slab_validate_pools( self )
slice.zero( to_zero )
slab_validate_pools( self )
log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", new_data_ptr, cast(rawptr) (uintptr(new_data_ptr) + uintptr(new_size - old_size))))
}
return
@ -204,7 +208,9 @@ slab_resize :: proc( using self : Slab,
// We'll need to provide an entirely new block, so the data will need to be copied over.
new_block : []byte
slab_validate_pools( self )
new_block, alloc_error = pool_grab( pool_resize )
slab_validate_pools( self )
if new_block == nil {
ensure(false, "Retreived a null block")
return
@ -223,7 +229,7 @@ slab_resize :: proc( using self : Slab,
pool_release( pool_old, data )
}
new_data = byte_slice( raw_data(new_block), int(old_size) )
new_data = new_block[ :new_size]
return
}
@ -235,6 +241,15 @@ slab_reset :: proc( slab : Slab )
}
}
slab_validate_pools :: proc( slab : Slab )
{
slab := slab
for id in 0 ..< slab.pools.idx {
pool := slab.pools.items[id]
pool_validate( pool )
}
}
slab_allocator_proc :: proc(
allocator_data : rawptr,
mode : AllocatorMode,

View File

@ -58,7 +58,7 @@ str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( cache : StringCache ) {
cache.slab, alloc_error = slab_init( & policy, allocator = persistent_allocator(), dbg_name = dbg_name )
verify(alloc_error == .None, "Failed to initialize the string cache" )
cache.table, alloc_error = zpl_hmap_init_reserve( StringCached, persistent_slab_allocator(), 64 * Kilobyte )
cache.table, alloc_error = zpl_hmap_init_reserve( StringCached, persistent_slab_allocator(), 8 )
return
}
@ -69,7 +69,7 @@ str_intern :: proc(
) -> StringCached
{
// profile(#procedure)
cache := get_state().string_cache
cache := & get_state().string_cache
key := u64( crc32( transmute([]byte) content ))
result := zpl_hmap_get( & cache.table, key )
@ -92,9 +92,13 @@ str_intern :: proc(
runes, alloc_error = to_runes( content, slab_allocator(cache.slab) )
verify( alloc_error == .None, "String cache had a backing allocator error" )
slab_validate_pools( get_state().persistent_slab )
// result, alloc_error = zpl_hmap_set( & cache.table, key, StringCached { transmute(string) byte_slice(str_mem, length), runes } )
result, alloc_error = zpl_hmap_set( & cache.table, key, StringCached { transmute(string) str_mem, runes } )
verify( alloc_error == .None, "String cache had a backing allocator error" )
slab_validate_pools( get_state().persistent_slab )
}
// profile_end()

View File

@ -45,6 +45,10 @@ Range2 :: struct #raw_union{
x0, y0 : f32,
x1, y1 : f32,
},
// TODO(Ed) : Test these
array : [4]f32,
mat : matrix[2, 2] f32,
}
range2 :: #force_inline proc "contextless" ( a, b : Vec2 ) -> Range2 {
@ -60,6 +64,12 @@ add_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> Range2 {
return result
}
sub_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> Range2 {
// result := Range2 { array = a.array - b.array }
result := Range2 { mat = a.mat - b.mat }
return result
}
equal_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> b32 {
result := a.p0 == b.p0 && a.p1 == b.p1
return b32(result)

View File

@ -89,9 +89,9 @@ PWS_ParseError :: struct {
}
PWS_ParseError_Max :: 32
PWS_TokenArray_ReserveSize :: Kilobyte * 64
PWS_NodeArray_ReserveSize :: Kilobyte * 64
PWS_LineArray_ReserveSize :: Kilobyte * 64
PWS_TokenArray_ReserveSize :: 8
PWS_NodeArray_ReserveSize :: 8
PWS_LineArray_ReserveSize :: 8
// TODO(Ed) : The ast arrays should be handled by a slab allocator dedicated to PWS_ASTs
// This can grow in undeterministic ways, persistent will get very polluted otherwise.

View File

@ -274,7 +274,7 @@ UI_Box :: struct {
UI_Layout_Stack_Size :: 512
UI_Style_Stack_Size :: 512
UI_Parent_Stack_Size :: 512
UI_Built_Boxes_Array_Size :: 512
UI_Built_Boxes_Array_Size :: 8 * Kilobyte
UI_State :: struct {
// TODO(Ed) : Use these

View File

@ -76,7 +76,7 @@ ui_compute_layout :: proc()
parent_content.min + parent_content_size * anchor.min,
parent_content.max - parent_content_size * anchor.max,
)
anchored_bounds_origin := (anchored_bounds.min + anchored_bounds.max) * 0.5
// anchored_bounds_origin := (anchored_bounds.min + anchored_bounds.max) * 0.5
// 2. Apply Margins
margins := range2(
@ -106,7 +106,12 @@ ui_compute_layout :: proc()
}
text_size : Vec2
text_size = cast(Vec2) measure_text_size( current.text.str, style.font, style.font_size, 0 )
if style.font_size == computed.text_size.y {
text_size = computed.text_size
}
else {
text_size = cast(Vec2) measure_text_size( current.text.str, style.font, style.font_size, 0 )
}
if size_to_text {
adjusted_size = text_size
@ -158,8 +163,6 @@ ui_compute_layout :: proc()
computed.padding = padding_bounds
computed.content = content_bounds
// TODO(Ed): Needs a rework based on changes to rest of layout above being changed
// Text
if len(current.text.str) > 0
{
content_size := content_bounds.max - content_bounds.min

@ -1 +1 @@
Subproject commit d9e318a22076638f91aa6c168c8c7f5f47f2ed6f
Subproject commit fe500e29040ef741cd507c4ce250d4183fa51852