From 8cbc70cb71381cf5b3001750ef72a4fdb2dd897c Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Fri, 20 Dec 2024 01:04:01 -0800 Subject: [PATCH] Use Open() and Create() functions instead of Initialize(). --- benchmarks/pool_allocator.cpp | 7 ++-- catkit_core/FreeListAllocator.cpp | 67 +++++++++++++++++++------------ catkit_core/FreeListAllocator.h | 11 +++-- catkit_core/PoolAllocator.cpp | 48 ++++++++++++++++------ catkit_core/PoolAllocator.h | 12 ++++-- 5 files changed, 92 insertions(+), 53 deletions(-) diff --git a/benchmarks/pool_allocator.cpp b/benchmarks/pool_allocator.cpp index 6dd2df38..d9357a16 100644 --- a/benchmarks/pool_allocator.cpp +++ b/benchmarks/pool_allocator.cpp @@ -9,8 +9,7 @@ void benchmark_linux_scalability() char *buffer = new char[PoolAllocator::CalculateMetadataBufferSize(CAPACITY)]; - PoolAllocator allocator(buffer); - allocator.Initialize(CAPACITY); + auto allocator = PoolAllocator::Create(buffer, CAPACITY); auto *handles = new PoolAllocator::BlockHandle[N]; @@ -18,12 +17,12 @@ void benchmark_linux_scalability() for (size_t i = 0; i < N; ++i) { - handles[i] = allocator.Allocate(); + handles[i] = allocator->Allocate(); } for (size_t i = 0; i < N; ++i) { - allocator.Deallocate(handles[i]); + allocator->Deallocate(handles[i]); } auto end = GetTimeStamp(); diff --git a/catkit_core/FreeListAllocator.cpp b/catkit_core/FreeListAllocator.cpp index 7c41dc4c..5d005068 100644 --- a/catkit_core/FreeListAllocator.cpp +++ b/catkit_core/FreeListAllocator.cpp @@ -55,16 +55,14 @@ void FreeListAllocator::BlockDescriptor::SetFree(const bool &is_free) m_SizeAndFreeFlag = (m_SizeAndFreeFlag & ~_FREE_FLAG) | (_FREE_FLAG * is_free); } -FreeListAllocator::FreeListAllocator(void *metadata_buffer) - : m_Header(*static_cast
(metadata_buffer)), +FreeListAllocator::FreeListAllocator(Header *header, std::shared_ptr block_allocator, Block *blocks) + : m_Header(*header), + m_BlockAllocator(block_allocator), + m_Blocks(blocks), m_MaxNumBlocks(m_Header.max_num_blocks), m_Head(m_Header.head), - m_Alignment(m_Header.alignment), - m_BlockAllocator(static_cast(metadata_buffer) + sizeof(Header)), - m_MetadataBuffer(metadata_buffer) + m_Alignment(m_Header.alignment) { - std::size_t block_list_offset = sizeof(Header) + PoolAllocator::CalculateMetadataBufferSize(m_MaxNumBlocks); - m_Blocks = reinterpret_cast(static_cast(m_MetadataBuffer) + block_list_offset); } std::size_t FreeListAllocator::ComputeMetadataBufferSize(std::size_t max_num_blocks) @@ -76,35 +74,52 @@ std::size_t FreeListAllocator::ComputeMetadataBufferSize(std::size_t max_num_blo return size; } +void FreeListAllocator::GetMemoryLayout(void *metadata_buffer, std::size_t max_num_blocks, void **block_allocator_memory, Block **blocks) +{ + std::size_t offset = sizeof(Header); + *block_allocator_memory = static_cast(static_cast(metadata_buffer) + offset); + + offset += PoolAllocator::CalculateMetadataBufferSize(max_num_blocks); + *blocks = reinterpret_cast(static_cast(metadata_buffer) + offset); +} + std::shared_ptr FreeListAllocator::Open(void *metadata_buffer) { - return std::shared_ptr(new FreeListAllocator(metadata_buffer)); + Header *header = static_cast
(metadata_buffer); + + void *block_allocator_memory; + Block *blocks; + GetMemoryLayout(metadata_buffer, header->max_num_blocks, &block_allocator_memory, &blocks); + + auto block_allocator = PoolAllocator::Open(block_allocator_memory); + + return std::shared_ptr(new FreeListAllocator(header, block_allocator, blocks)); } std::shared_ptr FreeListAllocator::Create(void *metadata_buffer, std::size_t max_num_blocks, std::size_t alignment, std::size_t buffer_size) { - auto allocator = std::shared_ptr(new FreeListAllocator(metadata_buffer)); + Header *header = static_cast
(metadata_buffer); - auto &header = allocator->m_Header; + void *block_allocator_memory; + Block *blocks; + GetMemoryLayout(metadata_buffer, header->max_num_blocks, &block_allocator_memory, &blocks); - std::copy(VERSION, VERSION + sizeof(VERSION), header.version); - header.max_num_blocks = max_num_blocks; - header.alignment = alignment; - header.total_buffer_size = buffer_size; + // Fill in the header information. + std::copy(VERSION, VERSION + sizeof(VERSION), header->version); + header->max_num_blocks = max_num_blocks; + header->alignment = alignment; + header->total_buffer_size = buffer_size; - // Initialize the internal allocator. - allocator->m_BlockAllocator.Initialize(max_num_blocks); + // Create the block allocator. + auto block_allocator = PoolAllocator::Create(block_allocator_memory, max_num_blocks); // Initialize the free list. - allocator->m_Head = allocator->m_BlockAllocator.Allocate(); - - std::size_t block_list_offset = sizeof(Header) + PoolAllocator::CalculateMetadataBufferSize(max_num_blocks); - allocator->m_Blocks = reinterpret_cast(static_cast(metadata_buffer) + block_list_offset); + header->head = block_allocator->Allocate(); - allocator->m_Blocks[allocator->m_Head].descriptor = BlockDescriptor(0, buffer_size, true); - allocator->m_Blocks[allocator->m_Head].next = INVALID_HANDLE; + blocks[header->head].descriptor = BlockDescriptor(0, buffer_size, true); + blocks[header->head].next = INVALID_HANDLE; - return allocator; + return std::shared_ptr(new FreeListAllocator(header, block_allocator, blocks)); } typename FreeListAllocator::BlockHandle FreeListAllocator::Allocate(std::size_t size) @@ -182,7 +197,7 @@ typename FreeListAllocator::BlockHandle FreeListAllocator::Allocate(std::size_t // We now have a block that is large enough to allocate the requested size. // Add a new block for the remaining free space. - PoolAllocator::BlockHandle allocated_block_handle = m_BlockAllocator.Allocate(); + PoolAllocator::BlockHandle allocated_block_handle = m_BlockAllocator->Allocate(); DEBUG_PRINT("Allocated block handle is " << allocated_block_handle); Block &allocated_block = m_Blocks[allocated_block_handle]; @@ -238,7 +253,7 @@ void FreeListAllocator::Deallocate(BlockHandle index) if (!owns_index) RemoveBlock(index); - m_BlockAllocator.Deallocate(index); + m_BlockAllocator->Deallocate(index); index = prev; owns_index = false; @@ -252,7 +267,7 @@ void FreeListAllocator::Deallocate(BlockHandle index) // The next block is no longer valid. Deallocate it. RemoveBlock(index); - m_BlockAllocator.Deallocate(index); + m_BlockAllocator->Deallocate(index); index = next; owns_index = false; diff --git a/catkit_core/FreeListAllocator.h b/catkit_core/FreeListAllocator.h index cc8194f8..b32c261e 100644 --- a/catkit_core/FreeListAllocator.h +++ b/catkit_core/FreeListAllocator.h @@ -10,9 +10,6 @@ // A simple lock-free free list allocator. class FreeListAllocator { -private: - FreeListAllocator(void *metadata_buffer); - public: using BlockHandle = PoolAllocator::BlockHandle; using Offset = std::uint32_t; @@ -85,17 +82,19 @@ class FreeListAllocator static_assert(offsetof(Header, head) == 16); static_assert(sizeof(Header) == 20); + FreeListAllocator(Header *header, std::shared_ptr block_allocator, Block *blocks); + + static void GetMemoryLayout(void *metadata_buffer, std::size_t max_num_blocks, void **block_allocator_memory, Block **blocks); + Header &m_Header; std::uint32_t &m_MaxNumBlocks; std::uint32_t &m_Alignment; std::atomic &m_Head; - PoolAllocator m_BlockAllocator; + std::shared_ptr m_BlockAllocator; Block *m_Blocks; - void *m_MetadataBuffer; - BlockHandle FindFirstFreeBlock(Size size); void InsertBlockSorted(BlockHandle index); diff --git a/catkit_core/PoolAllocator.cpp b/catkit_core/PoolAllocator.cpp index a5896020..715751d4 100644 --- a/catkit_core/PoolAllocator.cpp +++ b/catkit_core/PoolAllocator.cpp @@ -4,34 +4,56 @@ const std::uint8_t VERSION[4] = {0, 0, 0, 0}; -PoolAllocator::PoolAllocator(void *metadata_buffer) - : m_Header(*static_cast
(metadata_buffer)), - m_Capacity(m_Header.capacity), - m_Head(m_Header.head), - m_Next(reinterpret_cast(static_cast(metadata_buffer) + sizeof(Header))) +PoolAllocator::PoolAllocator(Header *header, std::atomic *next) + : m_Header(*header), + m_Next(next), + m_Capacity(m_Header.capacity), + m_Head(m_Header.head) { } -void PoolAllocator::Initialize(std::uint32_t capacity) +void PoolAllocator::GetMemoryLayout(void *metadata_buffer, std::atomic **next) { + *next = reinterpret_cast *>(static_cast(metadata_buffer) + sizeof(Header)); +} + +std::shared_ptr PoolAllocator::Create(void *metadata_buffer, std::uint32_t capacity) +{ + Header *header = static_cast(metadata_buffer); + + std::atomic *next; + GetMemoryLayout(metadata_buffer, &next); + // Set version and capacity. - std::copy(VERSION, VERSION + sizeof(VERSION), m_Header.version); - m_Capacity = capacity; + std::copy(VERSION, VERSION + sizeof(VERSION), header->version); + header->capacity = capacity; // Initialize the linked list. - m_Head.store(0, std::memory_order_relaxed); + header->head.store(0, std::memory_order_relaxed); - for (std::size_t i = 0; i < m_Capacity; ++i) + for (std::size_t i = 0; i < capacity; ++i) { - if (i == m_Capacity - 1) + if (i == capacity - 1) { - m_Next[i] = INVALID_HANDLE; + next[i] = INVALID_HANDLE; } else { - m_Next[i] = i + 1; + next[i] = i + 1; } } + + return std::shared_ptr(new PoolAllocator(header, next)); +} + +std::shared_ptr PoolAllocator::Open(void *metadata_buffer) +{ + Header *header = static_cast(metadata_buffer); + + std::atomic *next; + GetMemoryLayout(metadata_buffer, &next); + + return std::shared_ptr(new PoolAllocator(header, next)); } std::size_t PoolAllocator::CalculateMetadataBufferSize(std::uint32_t capacity) diff --git a/catkit_core/PoolAllocator.h b/catkit_core/PoolAllocator.h index 2558120a..33ffa267 100644 --- a/catkit_core/PoolAllocator.h +++ b/catkit_core/PoolAllocator.h @@ -5,6 +5,7 @@ #include #include #include +#include // A simple lock-free pool allocator. class PoolAllocator @@ -13,12 +14,11 @@ class PoolAllocator using BlockHandle = std::uint32_t; static const BlockHandle INVALID_HANDLE = std::numeric_limits::max(); - PoolAllocator(void *metadata_buffer); - - void Initialize(std::uint32_t capacity); - static std::size_t CalculateMetadataBufferSize(std::uint32_t capacity); + static std::shared_ptr Create(void *metadata_buffer, std::uint32_t capacity); + static std::shared_ptr Open(void *metadata_buffer); + BlockHandle Allocate(); void Deallocate(BlockHandle index); @@ -36,6 +36,10 @@ class PoolAllocator static_assert(offsetof(PoolAllocator::Header, head) == 8); static_assert(sizeof(PoolAllocator::Header) == 12); + PoolAllocator(Header *header, std::atomic *next); + + static void GetMemoryLayout(void *metadata_buffer, std::atomic **next); + Header &m_Header; std::uint32_t &m_Capacity;