Repository navigation
Expand file tree
/
Copy pathpool_allocator.cpp
More file actions
98 lines (84 loc) · 3.34 KB
/
Copy pathpool_allocator.cpp
File metadata and controls
98 lines (84 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "pool_allocator.hpp"
#include <iostream>
#include <cassert>
#include <vector>
#include <cstdint>
#include <cstring>
#include <cstddef>
#define TEST_ASSERT(cond) \
do { \
if (!(cond)) { \
std::cerr << "TEST FAILED AT LINE " << __LINE__ << ": " << #cond << std::endl; \
std::abort(); \
} \
} while (0)
static void test_alignment_and_growth() {
// PHASE 1: Bit-mask math verification
TEST_ASSERT(dynamic_pool_allocator::align_up(1, 256) == 256);
TEST_ASSERT(dynamic_pool_allocator::align_up(256, 256) == 256);
TEST_ASSERT(dynamic_pool_allocator::align_up(257, 256) == 512);
TEST_ASSERT(dynamic_pool_allocator::align_up(0, 256) == 0);
}
// PHASE 2: Compute allocation size verification
static void test_compute_alloc_size() {
TEST_ASSERT(dynamic_pool_allocator::compute_alloc_size(0) == 256);
TEST_ASSERT(dynamic_pool_allocator::compute_alloc_size(1) == 256);
TEST_ASSERT(dynamic_pool_allocator::compute_alloc_size(200) == 256);
TEST_ASSERT(dynamic_pool_allocator::compute_alloc_size(256) == 512);
TEST_ASSERT(dynamic_pool_allocator::compute_alloc_size(1024) == 1280);
}
// PHASE 3: Verify real OS memory allocation, 256-byte hardware address alignment, and pool caching
static void test_live_alloc_and_caching() {
dynamic_pool_allocator pool(4096);
size_t actual = 0;
void * ptr = pool.alloc(100, &actual);
TEST_ASSERT(ptr != nullptr);
TEST_ASSERT(actual == 256);
TEST_ASSERT((reinterpret_cast<uintptr_t>(ptr) % 256) == 0);
std::memset(ptr, 0xAA, actual);
pool.free_buffer(ptr, actual);
TEST_ASSERT(pool.get_cached_bytes() == 256);
}
// PHASE 4: Verify cache hit reuse, smallest-first budget eviction, and overflow guards
static void test_reuse_and_eviction() {
dynamic_pool_allocator pool(1024);
size_t s1 = 0;
void * p1 = pool.alloc(100, &s1);
TEST_ASSERT(p1 != nullptr);
pool.free_buffer(p1, s1);
size_t s2 = 0;
void * p2 = pool.alloc(200, &s2);
TEST_ASSERT(p2 == p1);
TEST_ASSERT(s2 == 256);
TEST_ASSERT(pool.get_cached_bytes() == 0);
// Allocate a second 768-byte block (500 + 12.5% = 562 -> 768)
size_t s3 = 0;
void * p3 = pool.alloc(500, &s3);
TEST_ASSERT(p3 != nullptr);
TEST_ASSERT(s3 == 768);
// Return both: 256 + 768 = 1024 (fits exact budget)
pool.free_buffer(p2, s2);
pool.free_buffer(p3, s3);
TEST_ASSERT(pool.get_cached_bytes() == 1024);
// Allocate another 512-byte block (300 + 12.5% = 337 -> 512) and free it:
// 1024 + 512 > 1024 budget -> must evict smallest (the 256-byte block) first, leaving 768 + 512 > 1024 -> evicts 768 too, leaving 512
size_t s4 = 0;
void * p4 = pool.alloc(300, &s4);
TEST_ASSERT(p4 != nullptr);
TEST_ASSERT(s4 == 512);
pool.free_buffer(p4, s4);
TEST_ASSERT(pool.get_cached_bytes() <= 1024);
// Overflow guard verification
size_t s_bad = 999;
void * p_bad = pool.alloc(dynamic_pool_allocator::MAX_REQUEST_SIZE + 1, &s_bad);
TEST_ASSERT(p_bad == nullptr);
TEST_ASSERT(s_bad == 0);
}
int main() {
test_alignment_and_growth();
test_compute_alloc_size();
test_live_alloc_and_caching();
test_reuse_and_eviction();
std::cout << "[PASS] All pool allocator tests succeeded.\n";
return 0;
}