Skip to content

Commit

Permalink
Refactor CF_Arena
Browse files Browse the repository at this point in the history
  • Loading branch information
RandyGaul committed Oct 14, 2024
1 parent 7ad2a36 commit 19b4e0e
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 28 deletions.
3 changes: 2 additions & 1 deletion docs/allocator/cf_arena_alloc.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/i
Allocates a block of memory aligned along a byte boundary.

```cpp
void* cf_arena_alloc(CF_Arena* arena, size_t size);
void* cf_arena_alloc(CF_Arena* arena, int size);
```
Parameters | Description
Expand All @@ -27,4 +27,5 @@ Returns an aligned pointer of `size` bytes.
## Related Pages
[cf_arena_init](/allocator/cf_arena_init.md)
[cf_arena_free](/allocator/cf_arena_free.md)
[cf_arena_reset](/allocator/cf_arena_reset.md)
34 changes: 34 additions & 0 deletions docs/allocator/cf_arena_free.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[//]: # (This file is automatically generated by Cute Framework's docs parser.)
[//]: # (Do not edit this file by hand!)
[//]: # (See: https://github.com/RandyGaul/cute_framework/blob/master/samples/docs_parser.cpp)
[](../header.md ':include')

# cf_arena_free

Category: [allocator](/api_reference?id=allocator)
GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/include/cute_alloc.h)
---

Frees the most recent allocation(s) from the arena.

```cpp
void cf_arena_free(CF_Arena* arena, int ptr);
```
Parameters | Description
--- | ---
arena | The arena from which to free memory.
size | The size of the most recent allocation to free.
## Remarks
This supports freeing memory in a Last-In-First-Out (LIFO) order, meaning
only the most recent allocation(s) can be freed. It does not support freeing allocations in
arbitrary order. Minimal error checking is performed, so only call this function if you
know what you're doing, otherwise you'll get memory corruption issues.
## Related Pages
[cf_arena_init](/allocator/cf_arena_init.md)
[cf_arena_alloc](/allocator/cf_arena_alloc.md)
[cf_arena_reset](/allocator/cf_arena_reset.md)
3 changes: 2 additions & 1 deletion docs/allocator/cf_arena_init.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/i
Initializes an arena for later allocations.

```cpp
void cf_arena_init(CF_Arena* arena, int alignment, int block_size);
CF_Arena cf_make_arena(int alignment, int block_size);
```
Parameters | Description
Expand All @@ -23,5 +23,6 @@ block_size | The default size of each internal call to `malloc` to form pages to
## Related Pages
[cf_arena_free](/allocator/cf_arena_free.md)
[cf_arena_alloc](/allocator/cf_arena_alloc.md)
[cf_arena_reset](/allocator/cf_arena_reset.md)
8 changes: 7 additions & 1 deletion docs/allocator/cf_arena_reset.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Category: [allocator](/api_reference?id=allocator)
GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/include/cute_alloc.h)
---

Free's up all resources used by the allocator and places it back into an initialized state.
Resets the allocator.

```cpp
void cf_arena_reset(CF_Arena* arena);
Expand All @@ -19,7 +19,13 @@ Parameters | Description
--- | ---
arena | The arena to reset.
## Remarks
This does not free up internal resources, and will reuse all previously allocated
resources to fulfill subsequent [cf_arena_alloc](/allocator/cf_arena_alloc.md) calls.
## Related Pages
[cf_arena_init](/allocator/cf_arena_init.md)
[cf_arena_alloc](/allocator/cf_arena_alloc.md)
[cf_arena_free](/allocator/cf_arena_free.md)
27 changes: 27 additions & 0 deletions docs/allocator/cf_destroy_arena.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[//]: # (This file is automatically generated by Cute Framework's docs parser.)
[//]: # (Do not edit this file by hand!)
[//]: # (See: https://github.com/RandyGaul/cute_framework/blob/master/samples/docs_parser.cpp)
[](../header.md ':include')

# cf_destroy_arena

Category: [allocator](/api_reference?id=allocator)
GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/include/cute_alloc.h)
---

Free's up all resources used by the allocator.

```cpp
void cf_destroy_arena(CF_Arena* arena);
```
Parameters | Description
--- | ---
arena | The arena to free.
## Related Pages
[cf_arena_init](/allocator/cf_arena_init.md)
[cf_arena_alloc](/allocator/cf_arena_alloc.md)
[cf_arena_reset](/allocator/cf_arena_reset.md)
[cf_arena_free](/allocator/cf_arena_free.md)
2 changes: 2 additions & 0 deletions docs/api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ This is a list of all functions in Cute Framework organized by categories. This
- [cf_allocator_override](/allocator/cf_allocator_override.md)
- [cf_allocator_restore_default](/allocator/cf_allocator_restore_default.md)
- [cf_arena_alloc](/allocator/cf_arena_alloc.md)
- [cf_arena_free](/allocator/cf_arena_free.md)
- [cf_arena_init](/allocator/cf_arena_init.md)
- [cf_arena_reset](/allocator/cf_arena_reset.md)
- [cf_calloc](/allocator/cf_calloc.md)
- [cf_destroy_arena](/allocator/cf_destroy_arena.md)
- [cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md)
- [cf_free](/allocator/cf_free.md)
- [cf_make_memory_pool](/allocator/cf_make_memory_pool.md)
Expand Down
48 changes: 38 additions & 10 deletions include/cute_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ typedef struct CF_Arena
int block_size;
char* ptr;
char* end;
char** blocks;
int block_index;
/* dyna */ char** blocks;
} CF_Arena;
// @end

Expand All @@ -166,9 +167,9 @@ typedef struct CF_Arena
* @param arena The arena to initialize.
* @param alignment An alignment boundary, must be a power of two.
* @param block_size The default size of each internal call to `malloc` to form pages to further allocate from.
* @related cf_arena_alloc cf_arena_reset
* @related cf_arena_init cf_arena_alloc cf_arena_reset cf_arena_free
*/
CF_API void CF_CALL cf_arena_init(CF_Arena* arena, int alignment, int block_size);
CF_API CF_Arena CF_CALL cf_make_arena(int alignment, int block_size);

/**
* @function cf_arena_alloc
Expand All @@ -177,19 +178,44 @@ CF_API void CF_CALL cf_arena_init(CF_Arena* arena, int alignment, int block_size
* @param arena The arena to allocate from.
* @param size The size of the allocation, it cannot be larger than `block_size` from `cf_arena_init`.
* @return Returns an aligned pointer of `size` bytes.
* @related cf_arena_init cf_arena_reset
* @related cf_arena_init cf_arena_alloc cf_arena_reset cf_arena_free
*/
CF_API void* CF_CALL cf_arena_alloc(CF_Arena* arena, size_t size);
CF_API void* CF_CALL cf_arena_alloc(CF_Arena* arena, int size);

/**
* @function cf_arena_free
* @category allocator
* @brief Frees the most recent allocation(s) from the arena.
* @param arena The arena from which to free memory.
* @param size The size of the most recent allocation to free.
* @remarks This supports freeing memory in a Last-In-First-Out (LIFO) order, meaning
* only the most recent allocation(s) can be freed. It does not support freeing allocations in
* arbitrary order. Minimal error checking is performed, so only call this function if you
* know what you're doing, otherwise you'll get memory corruption issues.
* @related cf_arena_init cf_arena_alloc cf_arena_reset cf_arena_free
*/
CF_API void CF_CALL cf_arena_free(CF_Arena* arena, int ptr);

/**
* @function cf_arena_reset
* @category allocator
* @brief Free's up all resources used by the allocator and places it back into an initialized state.
* @brief Resets the allocator.
* @param arena The arena to reset.
* @related cf_arena_init cf_arena_alloc
* @remarks This does not free up internal resources, and will reuse all previously allocated
* resources to fulfill subsequent `cf_arena_alloc` calls.
* @related cf_arena_init cf_arena_alloc cf_arena_reset cf_arena_free
*/
CF_API void CF_CALL cf_arena_reset(CF_Arena* arena);

/**
* @function cf_destroy_arena
* @category allocator
* @brief Free's up all resources used by the allocator.
* @param arena The arena to free.
* @related cf_arena_init cf_arena_alloc cf_arena_reset cf_arena_free
*/
CF_API void CF_CALL cf_destroy_arena(CF_Arena* arena);

//--------------------------------------------------------------------------------------------------
// Memory pool allocator.

Expand Down Expand Up @@ -251,9 +277,11 @@ namespace Cute
CF_INLINE void* aligned_alloc(size_t size, int alignment) { return cf_aligned_alloc(size, alignment); }
CF_INLINE void aligned_free(void* ptr) { return cf_aligned_free(ptr); }

CF_INLINE void arena_init(CF_Arena* arena, int alignment, int block_size) { cf_arena_init(arena, alignment, block_size); }
CF_INLINE void* arena_alloc(CF_Arena* arena, size_t size) { return cf_arena_alloc(arena, size); }
CF_INLINE void arena_reset(CF_Arena* arena) { return cf_arena_reset(arena); }
CF_INLINE CF_Arena make_arena(int alignment, int block_size) { return cf_make_arena(alignment, block_size); }
CF_INLINE void* arena_alloc(CF_Arena* arena, int size) { return cf_arena_alloc(arena, size); }
CF_INLINE void arena_free(CF_Arena* arena, int size) { cf_arena_free(arena, size); }
CF_INLINE void arena_reset(CF_Arena* arena) { cf_arena_reset(arena); }
CF_INLINE void destroy_arena(CF_Arena* arena) { cf_destroy_arena(arena); }

CF_INLINE CF_MemoryPool* make_memory_pool(int element_size, int element_count, int alignment) { return cf_make_memory_pool(element_size, element_count, alignment); }
CF_INLINE void destroy_memory_pool(CF_MemoryPool* pool) { cf_destroy_memory_pool(pool); }
Expand Down
4 changes: 3 additions & 1 deletion include/cute_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@
#define CF_ALIGN_TRUNCATE(v, n) ((v) & ~((n) - 1))
#define CF_ALIGN_FORWARD(v, n) CF_ALIGN_TRUNCATE((v) + (n) - 1, (n))
#define CF_ALIGN_TRUNCATE_PTR(p, n) ((void*)CF_ALIGN_TRUNCATE((uintptr_t)(p), n))
#define CF_ALIGN_FORWARD_PTR(p, n) ((void*)CF_ALIGN_FORWARD((uintptr_t)(p), n))
#define CF_ALIGN_FORWARD_PTR(p, n) ((void*)CF_ALIGN_FORWARD((uintptr_t)(p), n))// Align a value backward (truncate it down to the nearest alignment boundary)
#define CF_ALIGN_BACKWARD(v, n) CF_ALIGN_TRUNCATE((v), (n))
#define CF_ALIGN_BACKWARD_PTR(p, n) ((void*)CF_ALIGN_BACKWARD((uintptr_t)(p), n))
#define CF_GLOBAL

#ifdef __cplusplus
Expand Down
66 changes: 56 additions & 10 deletions src/cute_alloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,39 +105,85 @@ void cf_aligned_free(void* p)

//--------------------------------------------------------------------------------------------------

void cf_arena_init(CF_Arena* arena, int alignment, int block_size)
CF_Arena cf_make_arena(int alignment, int block_size)
{
CF_MEMSET(arena, 0, sizeof(*arena));
arena->alignment = alignment;
arena->block_size = block_size;
CF_Arena arena;
CF_MEMSET(&arena, 0, sizeof(arena));
arena.alignment = alignment;
arena.block_size = block_size;
return arena;
}

void* cf_arena_alloc(CF_Arena* arena, size_t size)
void* cf_arena_alloc(CF_Arena* arena, int size)
{
CF_ASSERT((int)size < arena->block_size);
if (size > (size_t)(arena->end - arena->ptr)) {
arena->ptr = (char*)cf_aligned_alloc(arena->block_size, arena->alignment);
if (size > (int)(arena->end - arena->ptr)) {
if (arena->block_index < asize(arena->blocks)) {
arena->ptr = arena->blocks[arena->block_index];
} else {
arena->ptr = (char*)cf_aligned_alloc(arena->block_size, arena->alignment);
apush(arena->blocks, arena->ptr);
}
arena->end = arena->ptr + arena->block_size;
apush(arena->blocks, arena->ptr);
arena->block_index++;
}
void* result = arena->ptr;
arena->ptr = (char*)CF_ALIGN_FORWARD_PTR(arena->ptr + size, arena->alignment);
CF_ASSERT(!(((size_t)(arena->ptr)) & (arena->alignment - 1)));
CF_ASSERT(!(((int)(uintptr_t)(arena->ptr)) & (arena->alignment - 1)));
CF_ASSERT(arena->ptr <= arena->end);
return result;
}

void cf_arena_free(CF_Arena* arena, int size)
{
CF_ASSERT(arena->block_index > 0);
char* aligned_ptr = (char*)CF_ALIGN_BACKWARD_PTR(arena->ptr - size, arena->alignment);
if (aligned_ptr >= arena->blocks[arena->block_index - 1]) {
arena->ptr = aligned_ptr;
} else {
int remaining_size = (int)(arena->ptr - arena->blocks[arena->block_index - 1]);
size -= remaining_size;
while (size > 0 && arena->block_index > 0) {
arena->block_index--;
CF_ASSERT(arena->block_index >= 0);
arena->ptr = arena->blocks[arena->block_index];
arena->end = arena->ptr + arena->block_size;
if (size < arena->block_size) {
arena->ptr = (char*)CF_ALIGN_BACKWARD_PTR(arena->end - size, arena->alignment);
size = 0;
} else {
size -= arena->block_size;
}
}
CF_ASSERT(size == 0);
}
}

void cf_arena_reset(CF_Arena* arena)
{
if (arena->blocks && asize(arena->blocks) > 0) {
arena->ptr = arena->blocks[0];
arena->end = arena->ptr + arena->block_size;
arena->block_index = 1;
} else {
arena->ptr = NULL;
arena->end = NULL;
arena->block_index = 0;
}
}

void cf_destroy_arena(CF_Arena* arena)
{
if (arena->blocks) {
for (int i = 0; i < alen(arena->blocks); ++i) {
for (int i = 0; i < asize(arena->blocks); ++i) {
cf_aligned_free(arena->blocks[i]);
}
afree(arena->blocks);
}
arena->ptr = NULL;
arena->end = NULL;
arena->blocks = NULL;
arena->block_index = 0;
}

//--------------------------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/cute_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ void cf_make_draw()
draw = CF_NEW(CF_Draw);
draw->projection = ortho_2d(0, 0, (float)app->w, (float)app->h);
draw->reset_cam();
cf_arena_init(&draw->uniform_arena, 32, CF_MB);
draw->uniform_arena = cf_make_arena(32, CF_MB);

// Mesh + vertex attributes.
Array<CF_VertexAttribute> attrs;
Expand Down
5 changes: 2 additions & 3 deletions src/cute_graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1522,8 +1522,8 @@ CF_RenderState cf_render_state_defaults()
CF_Material cf_make_material()
{
CF_MaterialInternal* material = CF_NEW(CF_MaterialInternal);
cf_arena_init(&material->uniform_arena, 4, 1024);
cf_arena_init(&material->block_arena, 4, 1024);
material->uniform_arena = cf_make_arena(4, 1024);
material->block_arena = cf_make_arena(4, 1024);
material->state = cf_render_state_defaults();
CF_Material result = { (uint64_t)material };
return result;
Expand Down Expand Up @@ -1763,7 +1763,6 @@ static void s_copy_uniforms(SDL_GPUCommandBuffer* cmd, CF_Arena* arena, CF_Shade
}
}

// @TODO Use a different allocation scheme that caches better.
cf_arena_reset(arena);
}

Expand Down

0 comments on commit 19b4e0e

Please sign in to comment.