Skip to content

Commit 8600079

Browse files
Introducing Memory Manager (#426)
* basic arena allocator * added resize impl * edit resize * added memory manager * updated CI * fixed format * fixed naming * assert PoolAllocator memory --------- Co-authored-by: jnyfah <[email protected]>
1 parent c8b35df commit 8600079

File tree

8 files changed

+315
-22
lines changed

8 files changed

+315
-22
lines changed

.github/workflows/Engine-CI.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
on:
22
push:
3-
branches: [ master, develop ]
3+
branches: [ master, develop, arena-integration ]
44
pull_request:
5-
branches: [ master, develop ]
5+
branches: [ master, develop, arena-integration ]
66

77
jobs:
88
clang-format:

ZEngine/ZEngine/Core/Memory/Allocator.cpp

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
namespace ZEngine::Core::Memory
66
{
7-
ArenaAllocator::~ArenaAllocator() {}
8-
97
void ArenaAllocator::Initialize(size_t size)
108
{
119
memory = (uint8_t*) malloc(size);
@@ -43,8 +41,6 @@ namespace ZEngine::Core::Memory
4341
return Allocate(size, alignment);
4442
}
4543

46-
void ArenaAllocator::Deallocate(void* pointer) {}
47-
4844
void* ArenaAllocator::Resize(void* old_memory, size_t old_size, size_t new_size, size_t alignment)
4945
{
5046
assert(Helpers::is_power_of_two(alignment) && "Alignment should be power of 2");
@@ -88,4 +84,96 @@ namespace ZEngine::Core::Memory
8884
current_offset = 0;
8985
}
9086

87+
ArenaTemp BeginTempArena(ArenaAllocator* arena)
88+
{
89+
ArenaTemp temp = {};
90+
temp.Arena = arena;
91+
temp.PreviousOffset = arena->previous_offset;
92+
temp.CurrentOffset = arena->current_offset;
93+
return temp;
94+
}
95+
96+
void EndTempArena(ArenaTemp tmp)
97+
{
98+
auto arena = tmp.Arena;
99+
arena->previous_offset = tmp.PreviousOffset;
100+
arena->current_offset = tmp.CurrentOffset;
101+
}
102+
103+
void PoolAllocator::Initialize(Arena* arena, size_t size, size_t chk_size, size_t alignment)
104+
{
105+
uintptr_t initial_start = (uintptr_t) &arena->memory[arena->current_offset];
106+
uintptr_t start = Helpers::memory_align(initial_start, (uintptr_t) alignment);
107+
size -= (size_t) (start - initial_start);
108+
109+
chk_size = Helpers::memory_align_size_t(chk_size, alignment);
110+
111+
assert(chk_size >= sizeof(PoolFreeNode) && "Chunk size is too small");
112+
assert(size >= chk_size && "Backing buffer length is smaller than the chunk size");
113+
114+
memory = (uint8_t*) arena->Allocate(size, alignment);
115+
116+
assert(memory && "Failed to allocate memory");
117+
118+
total_size = size;
119+
chunk_size = chk_size;
120+
head = nullptr;
121+
122+
Clear();
123+
}
124+
125+
void* PoolAllocator::Allocate()
126+
{
127+
PoolFreeNode* node = head;
128+
129+
if (node == nullptr)
130+
{
131+
return nullptr;
132+
}
133+
134+
head = head->Next;
135+
Helpers::secure_memset(node, 0, chunk_size, chunk_size);
136+
137+
return node;
138+
}
139+
140+
void* PoolAllocator::Allocate(const char* file, int line)
141+
{
142+
return Allocate();
143+
}
144+
145+
void PoolAllocator::Free(void* ptr)
146+
{
147+
if (!ptr)
148+
{
149+
return;
150+
}
151+
152+
auto start = memory;
153+
auto end = &memory[total_size];
154+
155+
if (!(start <= ptr && ptr < end))
156+
{
157+
return;
158+
}
159+
160+
PoolFreeNode* node = (PoolFreeNode*) (ptr);
161+
node->Next = head;
162+
head = node;
163+
}
164+
165+
void PoolAllocator::Clear()
166+
{
167+
auto chunk_count = total_size / chunk_size;
168+
size_t i = 0;
169+
170+
for (i = 0; i < chunk_count; i++)
171+
{
172+
void* ptr = &memory[i * chunk_size];
173+
PoolFreeNode* node = (PoolFreeNode*) ptr;
174+
// Push free node onto thte free list
175+
node->Next = head;
176+
head = node;
177+
}
178+
}
91179
} // namespace ZEngine::Core::Memory
Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
#pragma once
2+
#include <ZEngineDef.h>
23
#include <stddef.h>
34
#include <cstdint>
45

5-
#ifndef DEFAULT_ALIGNMENT
6-
#define DEFAULT_ALIGNMENT (2 * sizeof(void*))
7-
#endif // !DEFAULT_ALIGNMENT
8-
96
namespace ZEngine::Core::Memory
107
{
11-
struct Allocator
8+
struct ArenaAllocator;
9+
struct ArenaTemp;
10+
11+
struct ArenaTemp
1212
{
13-
virtual ~Allocator() {}
14-
virtual void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) = 0;
15-
virtual void* Allocate(size_t size, size_t alignment, const char* file, int line) = 0;
16-
virtual void Deallocate(void* pointer) = 0;
17-
}; // struct Allocator
13+
ArenaAllocator* Arena = nullptr;
14+
size_t CurrentOffset = 0;
15+
size_t PreviousOffset = 0;
16+
};
1817

19-
struct ArenaAllocator : public Allocator
18+
struct ArenaAllocator
2019
{
21-
virtual ~ArenaAllocator();
20+
~ArenaAllocator() {};
2221

2322
void Initialize(size_t size);
2423
void Shutdown();
2524

26-
void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) override;
27-
void* Allocate(size_t size, size_t alignment, const char* file, int line) override;
28-
void Deallocate(void* pointer) override;
25+
void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT);
26+
void* Allocate(size_t size, size_t alignment, const char* file, int line);
2927

3028
void* Resize(void* old_memory, size_t old_size, size_t new_size, size_t alignment = DEFAULT_ALIGNMENT);
3129
void Clear();
@@ -35,4 +33,35 @@ namespace ZEngine::Core::Memory
3533
size_t current_offset = 0;
3634
size_t previous_offset = 0;
3735
}; // struct ArenaAllocator
36+
37+
struct PoolFreeNode
38+
{
39+
PoolFreeNode* Next = nullptr;
40+
};
41+
42+
struct PoolAllocator
43+
{
44+
using Arena = ArenaAllocator;
45+
46+
~PoolAllocator() {};
47+
48+
void Initialize(Arena* arena, size_t size, size_t chunk_size, size_t alignment = DEFAULT_ALIGNMENT);
49+
50+
void* Allocate();
51+
void* Allocate(const char* file, int line);
52+
53+
void Free(void* ptr);
54+
void Clear();
55+
56+
uint8_t* memory = nullptr;
57+
PoolFreeNode* head = nullptr;
58+
size_t total_size = 0;
59+
size_t chunk_size = 0;
60+
};
61+
62+
ArenaTemp BeginTempArena(ArenaAllocator* arena);
63+
void EndTempArena(ArenaTemp arena);
3864
} // namespace ZEngine::Core::Memory
65+
66+
#define ZGetScratch(arena) ZEngine::Core::Memory::BeginTempArena(arena)
67+
#define ZReleaseScratch(scratch) ZEngine::Core::Memory::EndTempArena(scratch)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
#include <Allocator.h>
3+
4+
namespace ZEngine::Core::Memory
5+
{
6+
struct MemoryConfiguration
7+
{
8+
size_t DefaultSize = ZGiga(2ull);
9+
};
10+
11+
struct MemoryManager
12+
{
13+
void Initialize(const MemoryConfiguration& config)
14+
{
15+
this->ArenaAllocator.Initialize(config.DefaultSize);
16+
}
17+
18+
void Shutdowm()
19+
{
20+
ArenaAllocator.Shutdown();
21+
}
22+
23+
ArenaAllocator ArenaAllocator = {};
24+
};
25+
} // namespace ZEngine::Core::Memory

ZEngine/ZEngine/Helpers/MemoryOperations.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,20 @@ namespace ZEngine::Helpers
159159
return p;
160160
}
161161

162+
inline size_t memory_align_size_t(size_t ptr, size_t align)
163+
{
164+
size_t p, a, mod;
165+
166+
assert(is_power_of_two((uintptr_t) align) && "Alignment should be power of two");
167+
168+
p = ptr;
169+
a = align;
170+
mod = p & (a - 1);
171+
if (mod != 0)
172+
{
173+
p += a - mod;
174+
}
175+
return p;
176+
}
177+
162178
} // namespace ZEngine::Helpers

ZEngine/ZEngine/ZEngineDef.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,22 @@
4242
#define SINGLE_ARG(...) __VA_ARGS__
4343

4444
#define MAX_FILE_PATH_COUNT 256
45+
46+
/*
47+
* Allocator and Memory Macros
48+
*/
49+
#ifndef DEFAULT_ALIGNMENT
50+
#define DEFAULT_ALIGNMENT (2 * sizeof(void*))
51+
#endif // !DEFAULT_ALIGNMENT
52+
53+
#define ZKilo(size) (size * 1024)
54+
#define ZMega(size) (ZKilo(size) * 1024)
55+
#define ZGiga(size) (ZMega(size) * 1024)
56+
57+
#define ZPush(allocator, type, size) ((type*) (allocator)->Allocate(size, DEFAULT_ALIGNMENT, __FILE__, __LINE__))
58+
59+
#define ZPushArray(arena, type, count) ZPush(arena, type, (sizeof(type) * count))
60+
#define ZPushString(arena, count) ZPushArray(arena, char, count)
61+
#define ZPushStruct(arena, type) ZPushArray(arena, type, 1)
62+
63+
#define ZPushDynamicArray(pool, type) ((type*) (pool)->Allocate(__FILE__, __LINE__))

ZEngine/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ set (TEST_SOURCES
66
ThreadPool_test.cpp
77
handleManager_test.cpp
88
allocator_test.cpp
9+
../ZEngine/Core/Memory/Allocator.cpp
910
)
1011

1112
add_executable(ZEngineTests ${TEST_SOURCES})

0 commit comments

Comments
 (0)