diff --git a/src/base/base.h b/src/base/base.h index cbcb3cf..e99c551 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -11,6 +11,7 @@ extern "C" { #include "type_system/type_system.h" #include "../kprint/kprintf.h" #include "endian.h" +#include "memory/memory.h" #if __cplusplus } diff --git a/src/base/memory/CstdAllocator.c b/src/base/memory/CstdAllocator.c new file mode 100644 index 0000000..1df363c --- /dev/null +++ b/src/base/memory/CstdAllocator.c @@ -0,0 +1,18 @@ +#include "allocators_internal.h" + +void* CstdAllocator_alloc(allocator_t* self, size_t size){ + assert(size>0); + return malloc(size); +} + +void CstdAllocator_free(allocator_t* self, void* ptr){ + assert(ptr!=NULL); + free(ptr); +} + +void CstdAllocator_construct(CstdAllocator* self){ + self->base.alloc_f=CstdAllocator_alloc; + self->base.free_f=CstdAllocator_free; +} + +kt_define(CstdAllocator, NULL, NULL); diff --git a/src/base/memory/LinearAllocator.c b/src/base/memory/LinearAllocator.c new file mode 100644 index 0000000..75933e4 --- /dev/null +++ b/src/base/memory/LinearAllocator.c @@ -0,0 +1,84 @@ +#include "allocators_internal.h" + +#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 curr_chunk (self->chunks+self->curr_chunk_i) + +__attribute__ ((noinline)) void* ___alloc_realloc_chunk(LinearAllocator* self, size_t size){ + free(curr_chunk->data); + *curr_chunk=chunk_alloc(size, size); + return curr_chunk->data; +} + +__attribute__ ((noinline)) void* __alloc_new_chunk(LinearAllocator* self, size_t size){ + self->curr_chunk_i++; + // next chunk has been already allocated + if(self->curr_chunk_i < self->chunks_count) + return curr_chunk->data; + + // self->chunks array is full + if(self->chunks_count == self->max_chunks_count){ + self->max_chunks_count += chunks_per_allocation; + self->chunks = realloc(self->chunks, sizeof(MemoryChunk) * self->max_chunks_count); + } + + // new chunk allocation + self->chunks_count++; + size_t new_chunk_size=default_chunk_size > size ? size : default_chunk_size; + *curr_chunk=chunk_alloc(new_chunk_size, new_chunk_size); + return curr_chunk->data; +} + +void* LinearAllocator_alloc(allocator_t* _self, size_t size){ + // assert(_self!=NULL); + // assert(size>0); + LinearAllocator* self = (LinearAllocator*)_self; + size=add_padding(size); + + // aligned size can fit into the current chunk + if(curr_chunk->occupied_size + size <= curr_chunk->size){ + void* data_ptr=curr_chunk->data + curr_chunk->occupied_size; + curr_chunk->occupied_size += size; + return data_ptr; + } + // reallocation of current chunk because it is clean + if(curr_chunk->occupied_size == 0){ + // It is very unefficient operation. + // If it happens not only in the first chunk, code have to be refactored + assert(self->curr_chunk_i==0); + return ___alloc_realloc_chunk(self, size); + } + // creation of a new chunk + else { + return __alloc_new_chunk(self, size); + } +} + +void LinearAllocator_free(allocator_t* _self, void* ptr){ + // LinearAllocator can't free pointers +} + +void LinearAllocator_destruct(LinearAllocator* self){ + // assert(_self!=NULL); + for(u16 chunk_i=0; chunk_i < self->chunks_count; chunk_i++){ + free(self->chunks[chunk_i].data); + } + free(self->chunks); + self->chunks=NULL; +} + +void LinearAllocator_construct(LinearAllocator* self, size_t starting_size){ + assert(self!=NULL); + assert(starting_size>0); + self->base.alloc_f=LinearAllocator_alloc; + self->base.free_f=LinearAllocator_free; + + self->curr_chunk_i=0; + self->chunks_count=1; + self->max_chunks_count=chunks_per_allocation; + self->chunks=malloc(sizeof(*self->chunks) * chunks_per_allocation); + self->chunks[0]=chunk_alloc(starting_size, 0); +} + +kt_define(LinearAllocator, (freeMembers_t)LinearAllocator_destruct, NULL) diff --git a/src/base/memory/StackingAllocator.c b/src/base/memory/StackingAllocator.c new file mode 100644 index 0000000..d44edbf --- /dev/null +++ b/src/base/memory/StackingAllocator.c @@ -0,0 +1,58 @@ +#include "allocators_internal.h" + +#define chunk_alloc(SZ) (MemoryChunk){ .data=malloc(SZ), .size=SZ, .occupied_size=0 } +#define linear self->base +#define curr_chunk (linear.chunks+linear.curr_chunk_i) + +typedef struct { + size_t data_size; +} AllocationHeader; + +void* StackingAllocator_alloc(allocator_t* _self, size_t size){ + assert(_self!=NULL); + assert(size>0); + StackingAllocator* self = (StackingAllocator*)_self; + size=add_padding(size); + + // allocates memory with header struct before data + AllocationHeader* header_ptr=LinearAllocator_alloc(_self, sizeof(AllocationHeader) + size); + void* data_ptr = (void*)header_ptr + sizeof(AllocationHeader); + header_ptr->data_size = size; + + self->allocations_count++; + return data_ptr; +} + +void StackingAllocator_free(allocator_t* _self, void* data_ptr){ + assert(_self!=NULL); + assert(data_ptr!=NULL); + StackingAllocator* self = (StackingAllocator*)_self; + AllocationHeader* header_ptr = data_ptr - sizeof(AllocationHeader); + + // chunk is empty + if(curr_chunk->occupied_size==0){ + // isn't the first chunk + assert(linear.curr_chunk_i>0); + linear.curr_chunk_i--; + } + + size_t allocation_size=header_ptr->data_size+sizeof(*header_ptr); + // data must fit in chunk + assert(allocation_size <= curr_chunk->occupied_size); + curr_chunk->occupied_size -= allocation_size; +} + +void StackingAllocator_destruct(StackingAllocator* self){ + LinearAllocator_destruct(&self->base); +} + +void StackingAllocator_construct(StackingAllocator* self, size_t starting_size){ + assert(self!=NULL); + assert(starting_size>0); + LinearAllocator_construct(&linear, starting_size); + linear.base.alloc_f=StackingAllocator_alloc; + linear.base.free_f=StackingAllocator_free; + self->allocations_count=0; +} + +kt_define(StackingAllocator, (freeMembers_t)StackingAllocator_destruct, NULL) diff --git a/src/base/memory/allocators.c b/src/base/memory/allocators.c new file mode 100644 index 0000000..a2bd8ec --- /dev/null +++ b/src/base/memory/allocators.c @@ -0,0 +1,9 @@ +#include "memory.h" + +void* allocator_transfer(allocator_t* src, allocator_t* dest, void* data, size_t data_size) +{ + void* transfered=allocator_alloc(dest, data_size); + memcpy(transfered, data, data_size); + allocator_free(src, data); + return transfered; +} diff --git a/src/base/memory/allocators.h b/src/base/memory/allocators.h new file mode 100644 index 0000000..97f22bd --- /dev/null +++ b/src/base/memory/allocators.h @@ -0,0 +1,91 @@ +#pragma once + +#if __cplusplus +extern "C" { +#endif + +#include "../std.h" +#include "../type_system/ktDescriptor.h" + +/////////////////////////////////////////// +// MemoryAllocator interface // +/////////////////////////////////////////// + +typedef struct MemoryAllocator allocator_t; + +typedef void* (*alloc_t)(allocator_t*, size_t size); +typedef void (*free_t)(allocator_t*, void* ptr); + +typedef struct MemoryAllocator { + alloc_t alloc_f; + free_t free_f; +} allocator_t; + +#define allocator_alloc(ALLOCATOR, SIZE) \ + ((allocator_t*)ALLOCATOR)->alloc_f(ALLOCATOR, SIZE) +#define allocator_free(ALLOCATOR, PTR) \ + ((allocator_t*)ALLOCATOR)->free_f(ALLOCATOR, PTR) +#define allocator_destruct(ALLOCATOR) \ + ((allocator_t*)ALLOCATOR)->destruct_f(ALLOCATOR) + +void* allocator_transfer(allocator_t* src, allocator_t* dest, void* data, size_t data_size); + + +/////////////////////////////////////////// +// CstdAllocator // +/////////////////////////////////////////// +// Just wrapper for malloc() and free() // +/////////////////////////////////////////// + +STRUCT(CstdAllocator, + allocator_t base; +); + +void CstdAllocator_construct(CstdAllocator* self); + + +/////////////////////////////////////////// +// LinearAllocator // +/////////////////////////////////////////// +// Can't free allocated memory. // +// Allocates new memory chunk when the // +// current is full. // +/////////////////////////////////////////// + +typedef struct MemoryChunk { + void* data; + size_t size; + size_t occupied_size; /* free memory position in the current chunk. */ +} MemoryChunk; + +STRUCT(LinearAllocator, + allocator_t base; + MemoryChunk* chunks; /* MemoryChunk[max_chunks_count] */ + u16 chunks_count; /* allocated chunks */ + u16 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 */ +); + +void LinearAllocator_construct(LinearAllocator* self, size_t starting_size); +void LinearAllocator_destruct(LinearAllocator* self); + + +/////////////////////////////////////////// +// StackingAllocator // +/////////////////////////////////////////// +// The same as Linear, but can free // +// allocations in reverse order // +/////////////////////////////////////////// + +STRUCT(StackingAllocator, + LinearAllocator base; + u32 allocations_count; +); + +void StackingAllocator_construct(StackingAllocator* self, size_t starting_size); +void StackingAllocator_destruct(StackingAllocator* self); + + +#if __cplusplus +} +#endif diff --git a/src/base/memory/allocators_internal.h b/src/base/memory/allocators_internal.h new file mode 100644 index 0000000..da7fc88 --- /dev/null +++ b/src/base/memory/allocators_internal.h @@ -0,0 +1,4 @@ +#include +#include "memory.h" + +void* LinearAllocator_alloc(allocator_t* _self, size_t size); diff --git a/src/base/memory/memory.h b/src/base/memory/memory.h new file mode 100644 index 0000000..78c91f8 --- /dev/null +++ b/src/base/memory/memory.h @@ -0,0 +1,6 @@ +#include "allocators.h" + +// addresses must be aligned to this value +#define memory_align sizeof(void*) +// adds padding if memory_align if N isn't a multiple of memory_aligh +#define add_padding(N) (N + (N%memory_align != 0)*(memory_align - N%memory_align)) diff --git a/src/kprint/kprint.c b/src/kprint/kprint.c index 86161ba..046cf29 100644 --- a/src/kprint/kprint.c +++ b/src/kprint/kprint.c @@ -199,12 +199,12 @@ static const char* _kp_colorNames[16]={ "white" }; -char* kp_bgColor_toString(kp_fmt c){ +char* kp_bgColor_toString(kp_bgColor c){ u32 color_index=(c&0x00f00000)>>20; if(color_index>15) throw(ERR_WRONGINDEX); return _kp_colorNames[color_index]; } -char* kp_fgColor_toString(kp_fmt c){ +char* kp_fgColor_toString(kp_fgColor c){ u32 color_index=(c&0x00f00000)>>24; if(color_index>15) throw(ERR_WRONGINDEX); return _kp_colorNames[color_index]; diff --git a/tests/test_allocators.c b/tests/test_allocators.c new file mode 100644 index 0000000..153ffe4 --- /dev/null +++ b/tests/test_allocators.c @@ -0,0 +1,47 @@ +#include "tests.h" + +void _test_allocator(allocator_t* al){ + void* ptr=allocator_alloc(al, 1); + allocator_free(al, ptr); + ptr=allocator_alloc(al, 5); + allocator_free(al, ptr); + ptr=allocator_alloc(al, 41); + allocator_free(al, ptr); + ptr=allocator_alloc(al, 19); + void* ptr1=allocator_alloc(al, 1); + void* ptr2=allocator_alloc(al, 5); + // allocator_free(al, ptr); // temp case + allocator_free(al, ptr2); + allocator_free(al, ptr1); + allocator_free(al, ptr); + ptr=allocator_alloc(al, 500); + ptr1=allocator_alloc(al, 1025); + allocator_free(al, ptr1); + allocator_free(al, ptr);/* + ptr=allocator_alloc(al, 5000); + ptr1=allocator_alloc(al, 5000000); + allocator_free(al, ptr1); + allocator_free(al, ptr);*/ +} + + +void test_allocators(){ + kprintf("\e[96m----------[test_allocators]-----------\n"); + optime("test CstdAllocator", 10000, + CstdAllocator al; + CstdAllocator_construct(&al); + _test_allocator((allocator_t*)&al); + ); + optime("test LinearAllocator", 10000, + LinearAllocator al; + LinearAllocator_construct(&al, 4096); + _test_allocator((allocator_t*)&al); + LinearAllocator_destruct(&al); + ); + optime("test StackingAllocator", 10000, + StackingAllocator al; + StackingAllocator_construct(&al, 4096); + _test_allocator((allocator_t*)&al); + StackingAllocator_destruct(&al); + ); +} diff --git a/tests/tests.h b/tests/tests.h index b3cc22f..c8d9edf 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -6,6 +6,7 @@ extern "C" { #endif +void test_allocators(); void test_cptr(); void test_string(); void test_safethrow(); @@ -20,22 +21,23 @@ void test_kprint_colors(); void test_kprint(); void test_type_system(); -inline void test_all(){ +static inline void test_all(){ kprintf("\e[97mkerep tests are starting!\n"); optime(__func__, 1, - test_cptr(); - test_type_system(); + test_allocators(); + /*test_cptr(); test_string(); test_safethrow(); test_searchtree(); test_autoarr(); + test_hash_functions(); + test_hashtable(); + test_dtsod(); test_autoarrVsVector(); test_rng_algorithms(); test_kprint_colors(); test_kprint(); - test_hash_functions(); - test_hashtable(); - test_dtsod(); + test_type_system();*/ kprintf("\e[96m--------------------------------------\e[0m\n"); ); }