memory allocators
This commit is contained in:
parent
490d450a82
commit
a983df1ac6
@ -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
|
||||
}
|
||||
|
||||
18
src/base/memory/CstdAllocator.c
Normal file
18
src/base/memory/CstdAllocator.c
Normal file
@ -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);
|
||||
84
src/base/memory/LinearAllocator.c
Normal file
84
src/base/memory/LinearAllocator.c
Normal file
@ -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)
|
||||
58
src/base/memory/StackingAllocator.c
Normal file
58
src/base/memory/StackingAllocator.c
Normal file
@ -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)
|
||||
9
src/base/memory/allocators.c
Normal file
9
src/base/memory/allocators.c
Normal file
@ -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;
|
||||
}
|
||||
91
src/base/memory/allocators.h
Normal file
91
src/base/memory/allocators.h
Normal file
@ -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
|
||||
4
src/base/memory/allocators_internal.h
Normal file
4
src/base/memory/allocators_internal.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <assert.h>
|
||||
#include "memory.h"
|
||||
|
||||
void* LinearAllocator_alloc(allocator_t* _self, size_t size);
|
||||
6
src/base/memory/memory.h
Normal file
6
src/base/memory/memory.h
Normal file
@ -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))
|
||||
@ -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];
|
||||
|
||||
47
tests/test_allocators.c
Normal file
47
tests/test_allocators.c
Normal file
@ -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);
|
||||
);
|
||||
}
|
||||
@ -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");
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user