LinearAllocator improved

This commit is contained in:
timerix 2023-06-08 21:29:47 +06:00
parent 8d36fd8042
commit 28169450cf
10 changed files with 73 additions and 51 deletions

View File

@ -1,14 +1,16 @@
## General refactoring ## Allocators
- replace all malloc() and free() with allocator_alloc() and allocator_free() - replace all malloc() and free() with allocator_alloc() and allocator_free()
- replace allocating constructors with Type_init(var_ptr, ...) - replace allocating constructors with Type_construct(var_ptr, ...)
- replace Struct_free functions with Struct_destruct which will not call free() on the struct ptr - replace Struct_free functions with Struct_destruct which will not call free() on the struct ptr
- store in resizable structs their buffer allocators and free them with Struct_destruct() - store in resizable structs their buffer allocators and free them with Struct_destruct()
- check allocator_free call order - check allocator_free call order
- deal with StackingAllocator_free not freing memory sometimes
- replace LinearAllocator with StackingAllocator when possible (in DtsodV24_deserialize) - replace LinearAllocator with StackingAllocator when possible (in DtsodV24_deserialize)
## Autoarr ## Autoarr
- store lenght and max_lenght inside the struct instead of calculating them by macro - store lenght and max_lenght inside the struct instead of calculating them by macro
- keep Autoarr_length() and Autoarr_maxLength() to old code compatibility - keep Autoarr_length() and Autoarr_maxLength() to old code compatibility
- toString()
## Hashtable ## Hashtable
- store hash in KVPair - store hash in KVPair

View File

@ -6,7 +6,7 @@ Autoarr_define(KVPair, false)
// proper way to clean a KVP // proper way to clean a KVP
void KVPair_destruct(KVPair p){ void KVPair_destruct(KVPair p){
free(p.key); // free(p.key);
Unitype_destruct(&p.value); Unitype_destruct(&p.value);
} }
void __KVPair_destruct(void* p){ KVPair_destruct(*(KVPair*)p); } void __KVPair_destruct(void* p){ KVPair_destruct(*(KVPair*)p); }

View File

@ -1,6 +1,6 @@
#include "allocators_internal.h" #include "allocators_internal.h"
void* CstdAllocator_alloc(allocator_ptr self, size_t size){ void* CstdAllocator_alloc(allocator_ptr self, alloc_size_t size){
// assert(size>0); // assert(size>0);
return malloc(size); return malloc(size);
} }

View File

@ -1,17 +1,27 @@
#include "allocators_internal.h" #include "allocators_internal.h"
#include <stdio.h>
#define default_chunks_per_allocation 16
// growing chunk array size
#define new_max_chunks_count ( default_chunks_per_allocation*(self->chunks_count/16 == 0) + \
default_chunks_per_allocation*add_padding(self->chunks_count/2)/4 )
#define default_chunk_size 1024
// growing chunk size
#define new_chunk_size ( default_chunk_size*(self->chunks_count/16 == 0) + \
default_chunk_size*add_padding(self->chunks_count/8) )
#define chunks_per_allocation 16
#define default_chunk_size add_padding(1024)
#define chunk_alloc(SZ, OCCUPIED) (MemoryChunk){ .data=malloc(SZ), .size=SZ, .occupied_size=OCCUPIED } #define chunk_alloc(SZ, OCCUPIED) (MemoryChunk){ .data=malloc(SZ), .size=SZ, .occupied_size=OCCUPIED }
#define curr_chunk (self->chunks+self->curr_chunk_i) #define curr_chunk (self->chunks+self->curr_chunk_i)
__attribute__ ((noinline)) void* ___alloc_realloc_chunk(LinearAllocator* self, size_t size){ __attribute__ ((noinline)) void* ___alloc_realloc_chunk(LinearAllocator* self, alloc_size_t alloc_size){
free(curr_chunk->data); free(curr_chunk->data);
*curr_chunk=chunk_alloc(size, size); *curr_chunk=chunk_alloc(alloc_size, alloc_size);
return curr_chunk->data; return curr_chunk->data;
} }
__attribute__ ((noinline)) void* __alloc_new_chunk(LinearAllocator* self, size_t size){ __attribute__ ((noinline)) void* __alloc_new_chunk(LinearAllocator* self, alloc_size_t alloc_size){
self->curr_chunk_i++; self->curr_chunk_i++;
// next chunk has been already allocated // next chunk has been already allocated
if(self->curr_chunk_i < self->chunks_count) if(self->curr_chunk_i < self->chunks_count)
@ -19,27 +29,27 @@ __attribute__ ((noinline)) void* __alloc_new_chunk(LinearAllocator* self, size_t
// self->chunks array is full // self->chunks array is full
if(self->chunks_count == self->max_chunks_count){ if(self->chunks_count == self->max_chunks_count){
self->max_chunks_count += chunks_per_allocation; self->max_chunks_count = new_max_chunks_count;
self->chunks = realloc(self->chunks, sizeof(MemoryChunk) * self->max_chunks_count); self->chunks = realloc(self->chunks, sizeof(MemoryChunk) * self->max_chunks_count);
} }
// new chunk allocation // new chunk allocation
self->chunks_count++; self->chunks_count++;
size_t new_chunk_size=default_chunk_size > size ? size : default_chunk_size; alloc_size_t _new_chunk_size= alloc_size > new_chunk_size ? alloc_size : new_chunk_size;
*curr_chunk=chunk_alloc(new_chunk_size, new_chunk_size); *curr_chunk=chunk_alloc(_new_chunk_size, alloc_size);
return curr_chunk->data; return curr_chunk->data;
} }
void* LinearAllocator_alloc(allocator_ptr _self, size_t size){ void* LinearAllocator_alloc(allocator_ptr _self, alloc_size_t alloc_size){
// assert(_self!=NULL); // assert(_self!=NULL);
// assert(size>0); // assert(alloc_size>0);
LinearAllocator* self = (LinearAllocator*)_self; LinearAllocator* self = (LinearAllocator*)_self;
size=add_padding(size); alloc_size=add_padding(alloc_size);
// aligned size can fit into the current chunk // aligned alloc_size can fit into the current chunk
if(curr_chunk->occupied_size + size <= curr_chunk->size){ if(curr_chunk->occupied_size + alloc_size <= curr_chunk->size){
void* data_ptr=curr_chunk->data + curr_chunk->occupied_size; void* data_ptr=curr_chunk->data + curr_chunk->occupied_size;
curr_chunk->occupied_size += size; curr_chunk->occupied_size += alloc_size;
return data_ptr; return data_ptr;
} }
// reallocation of current chunk because it is clean // reallocation of current chunk because it is clean
@ -47,11 +57,11 @@ void* LinearAllocator_alloc(allocator_ptr _self, size_t size){
// It is very unefficient operation. // It is very unefficient operation.
// If it happens not only in the first chunk, code have to be refactored // If it happens not only in the first chunk, code have to be refactored
assert(self->curr_chunk_i==0); assert(self->curr_chunk_i==0);
return ___alloc_realloc_chunk(self, size); return ___alloc_realloc_chunk(self, alloc_size);
} }
// creation of a new chunk // creation of a new chunk
else { else {
return __alloc_new_chunk(self, size); return __alloc_new_chunk(self, alloc_size);
} }
} }
@ -61,14 +71,22 @@ void LinearAllocator_free(allocator_ptr _self, void* ptr){
void LinearAllocator_destruct(LinearAllocator* self){ void LinearAllocator_destruct(LinearAllocator* self){
// assert(_self!=NULL); // assert(_self!=NULL);
for(u16 chunk_i=0; chunk_i < self->chunks_count; chunk_i++){ u32 size=0;
u32 oc_size=0;
for(u32 chunk_i=0; chunk_i < self->chunks_count; chunk_i++){
free(self->chunks[chunk_i].data); free(self->chunks[chunk_i].data);
size+=self->chunks[chunk_i].size;
oc_size+=self->chunks[chunk_i].occupied_size;
} }
printf("\e[35m%u/%u\n",oc_size,size);
free(self->chunks); free(self->chunks);
self->chunks=NULL; self->chunks=NULL;
self->chunks_count=0;
self->curr_chunk_i=0;
self->max_chunks_count=0;
} }
void LinearAllocator_construct(LinearAllocator* self, size_t starting_size){ void LinearAllocator_construct(LinearAllocator* self, alloc_size_t starting_size){
assert(self!=NULL); assert(self!=NULL);
assert(starting_size>0); assert(starting_size>0);
self->base.alloc_f=LinearAllocator_alloc; self->base.alloc_f=LinearAllocator_alloc;
@ -76,8 +94,8 @@ void LinearAllocator_construct(LinearAllocator* self, size_t starting_size){
self->curr_chunk_i=0; self->curr_chunk_i=0;
self->chunks_count=1; self->chunks_count=1;
self->max_chunks_count=chunks_per_allocation; self->max_chunks_count=new_max_chunks_count;
self->chunks=malloc(sizeof(*self->chunks) * chunks_per_allocation); self->chunks=malloc(sizeof(MemoryChunk) * new_max_chunks_count);
self->chunks[0]=chunk_alloc(starting_size, 0); self->chunks[0]=chunk_alloc(starting_size, 0);
} }

View File

@ -5,10 +5,10 @@
#define curr_chunk (linear.chunks+linear.curr_chunk_i) #define curr_chunk (linear.chunks+linear.curr_chunk_i)
typedef struct { typedef struct {
size_t data_size; alloc_size_t data_size;
} AllocationHeader; } AllocationHeader;
void* StackingAllocator_alloc(allocator_ptr _self, size_t size){ void* StackingAllocator_alloc(allocator_ptr _self, alloc_size_t size){
assert(_self!=NULL); assert(_self!=NULL);
assert(size>0); assert(size>0);
StackingAllocator* self = (StackingAllocator*)_self; StackingAllocator* self = (StackingAllocator*)_self;
@ -36,7 +36,7 @@ void StackingAllocator_free(allocator_ptr _self, void* data_ptr){
linear.curr_chunk_i--; linear.curr_chunk_i--;
} }
size_t allocation_size=header_ptr->data_size+sizeof(*header_ptr); alloc_size_t allocation_size=header_ptr->data_size+sizeof(*header_ptr);
// data must fit in chunk // data must fit in chunk
assert(allocation_size <= curr_chunk->occupied_size); assert(allocation_size <= curr_chunk->occupied_size);
curr_chunk->occupied_size -= allocation_size; curr_chunk->occupied_size -= allocation_size;
@ -46,7 +46,7 @@ void StackingAllocator_destruct(StackingAllocator* self){
LinearAllocator_destruct(&self->base); LinearAllocator_destruct(&self->base);
} }
void StackingAllocator_construct(StackingAllocator* self, size_t starting_size){ void StackingAllocator_construct(StackingAllocator* self, alloc_size_t starting_size){
assert(self!=NULL); assert(self!=NULL);
assert(starting_size>0); assert(starting_size>0);
LinearAllocator_construct(&linear, starting_size); LinearAllocator_construct(&linear, starting_size);

View File

@ -10,9 +10,11 @@ extern "C" {
// MemoryAllocator interface // // MemoryAllocator interface //
/////////////////////////////////////////// ///////////////////////////////////////////
typedef struct MemoryAllocator* allocator_ptr; typedef u32 alloc_size_t;
typedef struct MemoryAllocator MemoryAllocator;
typedef MemoryAllocator* allocator_ptr;
typedef void* (*alloc_t)(allocator_ptr, size_t size); typedef void* (*alloc_t)(allocator_ptr, alloc_size_t size);
typedef void (*free_t)(allocator_ptr, void* ptr); typedef void (*free_t)(allocator_ptr, void* ptr);
typedef struct MemoryAllocator { typedef struct MemoryAllocator {
@ -27,7 +29,7 @@ typedef struct MemoryAllocator {
#define allocator_destruct(ALLOCATOR) \ #define allocator_destruct(ALLOCATOR) \
((allocator_ptr)ALLOCATOR)->destruct_f(ALLOCATOR) ((allocator_ptr)ALLOCATOR)->destruct_f(ALLOCATOR)
void* allocator_transfer(allocator_ptr src, allocator_ptr dest, void* data, size_t data_size); void* allocator_transfer(allocator_ptr src, allocator_ptr dest, void* data, alloc_size_t data_size);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,6 +1,6 @@
#include "memory.h" #include "memory.h"
void* allocator_transfer(allocator_ptr src, allocator_ptr dest, void* data, size_t data_size) void* allocator_transfer(allocator_ptr src, allocator_ptr dest, void* data, alloc_size_t data_size)
{ {
void* transfered=allocator_alloc(dest, data_size); void* transfered=allocator_alloc(dest, data_size);
memcpy(transfered, data, data_size); memcpy(transfered, data, data_size);

View File

@ -31,19 +31,19 @@ void CstdAllocator_construct(CstdAllocator* self);
typedef struct MemoryChunk { typedef struct MemoryChunk {
void* data; void* data;
size_t size; alloc_size_t size;
size_t occupied_size; /* free memory position in the current chunk. */ alloc_size_t occupied_size; /* free memory position in the current chunk. */
} MemoryChunk; } MemoryChunk;
STRUCT(LinearAllocator, STRUCT(LinearAllocator,
MemoryAllocator base; MemoryAllocator base;
MemoryChunk* chunks; /* MemoryChunk[max_chunks_count] */ MemoryChunk* chunks; /* MemoryChunk[max_chunks_count] */
u16 chunks_count; /* allocated chunks */ u32 chunks_count; /* allocated chunks */
u16 max_chunks_count; /* chunks that can be allocated without reallocating .chunks */ u32 max_chunks_count; /* chunks that can be allocated without reallocating .chunks */
u16 curr_chunk_i; /* index of current chunk in .chunks, can be < .chunks_count */ u32 curr_chunk_i; /* index of current chunk in .chunks, can be < .chunks_count */
); );
void LinearAllocator_construct(LinearAllocator* self, size_t starting_size); void LinearAllocator_construct(LinearAllocator* self, alloc_size_t starting_size);
void LinearAllocator_destruct(LinearAllocator* self); void LinearAllocator_destruct(LinearAllocator* self);
@ -59,7 +59,7 @@ STRUCT(StackingAllocator,
u32 allocations_count; u32 allocations_count;
); );
void StackingAllocator_construct(StackingAllocator* self, size_t starting_size); void StackingAllocator_construct(StackingAllocator* self, alloc_size_t starting_size);
void StackingAllocator_destruct(StackingAllocator* self); void StackingAllocator_destruct(StackingAllocator* self);

View File

@ -1,4 +1,4 @@
#include <assert.h> #include <assert.h>
#include "memory.h" #include "memory.h"
void* LinearAllocator_alloc(allocator_ptr _self, size_t size); void* LinearAllocator_alloc(allocator_ptr _self, alloc_size_t size);

View File

@ -24,19 +24,19 @@ void test_type_system();
static inline void test_all(){ static inline void test_all(){
kprintf("\e[97mkerep tests are starting!\n"); kprintf("\e[97mkerep tests are starting!\n");
optime(__func__, 1, optime(__func__, 1,
test_type_system(); // test_type_system();
test_allocators(); // test_allocators();
test_kprint_colors(); // test_kprint_colors();
test_kprint(); // test_kprint();
test_safethrow(); // test_safethrow();
test_rng_algorithms(); // test_rng_algorithms();
test_cptr(); // test_cptr();
test_string(); // test_string();
// test_searchtree(); // test_searchtree();
test_autoarr(); // test_autoarr();
test_autoarrVsVector(); // test_autoarrVsVector();
// test_hash_functions(); /* long test */ // test_hash_functions(); /* long test */
// test_hashtable(); test_hashtable();
// test_dtsod(); // test_dtsod();
kprintf("\e[96m--------------------------------------\e[0m\n"); kprintf("\e[96m--------------------------------------\e[0m\n");
); );