Start to setup the other allocators I'm going to roll my own of, also created a string interning file
This commit is contained in:
parent
898f359470
commit
3c8abc5333
45
code/grime_arena.odin
Normal file
45
code/grime_arena.odin
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
The default arena allocator Odin provides does fragmented resizes even for the last most allocated block getting resized.
|
||||
This is an alternative to alleviates that.
|
||||
*/
|
||||
package sectr
|
||||
|
||||
ArenaFixedHeader :: struct {
|
||||
data : []byte,
|
||||
offset : uint,
|
||||
peak_used : uint,
|
||||
}
|
||||
|
||||
ArenaFixed :: struct {
|
||||
using header : ^ArenaFixedHeader,
|
||||
}
|
||||
|
||||
arena_fixed_init :: proc( backing : []byte ) -> (arena : ArenaFixed) {
|
||||
header_size := size_of(ArenaFixedHeader)
|
||||
|
||||
verify(len(backing) >= (header_size + Kilobyte), "Attempted to init an arena with less than kilobyte of memory...")
|
||||
|
||||
arena.header = cast(^ArenaFixedHeader) raw_data(backing)
|
||||
using arena.header
|
||||
data_ptr := cast([^]byte) (cast( [^]ArenaFixedHeader) arena.header)[ 1:]
|
||||
data = slice_ptr( data_ptr, len(backing) - header_size )
|
||||
offset = 0
|
||||
peak_used = 0
|
||||
return
|
||||
}
|
||||
|
||||
arena_fixed_allocator_proc :: proc(
|
||||
allocator_data : rawptr,
|
||||
mode : AllocatorMode,
|
||||
size : int,
|
||||
alignment : int,
|
||||
old_memory : rawptr,
|
||||
old_size : int,
|
||||
location := #caller_location
|
||||
) -> ([]byte, AllocatorError)
|
||||
{
|
||||
|
||||
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
45
code/grime_pool_allocator.odin
Normal file
45
code/grime_pool_allocator.odin
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
This is a pool allocator setup to grow incrementally via buckets.
|
||||
Buckets are stored in singly-linked lists so that they be allocated non-contiguous
|
||||
*/
|
||||
package sectr
|
||||
|
||||
Pool :: struct {
|
||||
using header : ^PoolHeader,
|
||||
}
|
||||
|
||||
PoolHeader :: struct {
|
||||
backing : Allocator,
|
||||
|
||||
block_size : uint,
|
||||
bucket_capacity : uint,
|
||||
out_band_size : uint,
|
||||
alignment : uint,
|
||||
|
||||
free_list : LL_Node( [^]byte),
|
||||
buckets : LL_Node( [^]byte),
|
||||
current_bucket : ^byte,
|
||||
}
|
||||
|
||||
PoolBucket :: struct ( $ Type : typeid) {
|
||||
blocks : [^]Type,
|
||||
}
|
||||
|
||||
pool_allocator :: proc ( using self : Pool ) -> (allocator : Allocator) {
|
||||
allocator.procedure = pool_allocator_proc
|
||||
allocator.data = self.header
|
||||
return
|
||||
}
|
||||
|
||||
pool_allocator_proc :: proc(
|
||||
allocator_data : rawptr,
|
||||
mode : AllocatorMode,
|
||||
size : int,
|
||||
alignment : int,
|
||||
old_memory : rawptr,
|
||||
old_size : int,
|
||||
loc := #caller_location
|
||||
) -> ([]byte, AllocatorError)
|
||||
{
|
||||
return nil, AllocatorError.Mode_Not_Implemented
|
||||
}
|
@ -1,5 +1,63 @@
|
||||
/* Slab Allocator
|
||||
These are a collection of pool allocators serving as a general way
|
||||
to allocate a large amount of dynamic sized data.
|
||||
|
||||
The usual use case for this is an arena, stack,
|
||||
or dedicated pool allocator fail to be enough to handle a data structure
|
||||
that either is too random with its size (ex: strings)
|
||||
or is intended to grow an abitrary degree with an unknown upper bound (dynamic arrays, and hashtables).
|
||||
|
||||
The protototype will use slab allocators for two purposes:
|
||||
* String interning
|
||||
* General purpose set for handling large arrays & hash tables within some underlying arena or stack.
|
||||
|
||||
Technically speaking the general purpose situations can instead be grown on demand
|
||||
with a dedicated segement of vmem, however this might be overkill
|
||||
if the worst case buckets allocated are < 500 mb for most app usage.
|
||||
|
||||
The slab allocators are expected to hold growable pool allocators,
|
||||
where each pool stores a 'bucket' of fixed-sized blocks of memory.
|
||||
When a pools bucket is full it will request another bucket from its arena
|
||||
for permanent usage within the arena's lifetime.
|
||||
|
||||
A freelist is tracked for free-blocks for each pool (provided by the underlying pool allocator)
|
||||
|
||||
A slab starts out with pools initialized with no buckets and grows as needed.
|
||||
When a slab is initialized the slab policy is provided to know how many size-classes there should be
|
||||
which each contain the ratio of bucket to block size.
|
||||
|
||||
Strings Slab pool size-classes (bucket:block ratio) are as follows:
|
||||
16 mb : 64 b = 262,144 blocks
|
||||
8 mb : 128 b = 8192 blocks
|
||||
8 mb : 256 b = 8192 blocks
|
||||
8 mb : 1 kb = 8192 blocks
|
||||
16 mb : 4 kb = 4096 blocks
|
||||
32 mb : 16 kb = 4096 blocks
|
||||
32 mb : 32 kb = 4096 blocks
|
||||
256 mb : 64 kb =
|
||||
512 mb : 128 kb =
|
||||
*/
|
||||
package sectr
|
||||
|
||||
SlabSizeClass :: struct {
|
||||
bucket : uint,
|
||||
block : uint,
|
||||
}
|
||||
|
||||
Slab_Max_Size_Classes :: 32
|
||||
|
||||
SlabPolicy :: [Slab_Max_Size_Classes]SlabSizeClass
|
||||
|
||||
SlabHeader :: struct {
|
||||
policy : SlabPolicy,
|
||||
pools : [Slab_Max_Size_Classes]Pool,
|
||||
}
|
||||
|
||||
Slab :: struct {
|
||||
using header : SlabHeader,
|
||||
}
|
||||
|
||||
slab_init_reserve :: proc( ) -> ( Slab )
|
||||
{
|
||||
return {}
|
||||
}
|
||||
|
1
code/grime_string_interning.odin
Normal file
1
code/grime_string_interning.odin
Normal file
@ -0,0 +1 @@
|
||||
package sectr
|
Loading…
Reference in New Issue
Block a user