diff --git a/CMakeLists.txt b/CMakeLists.txt index 60783e5..e3e9fe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.1.45) +project(blt-gp VERSION 0.1.46) include(CTest) diff --git a/include/blt/gp/fwdecl.h b/include/blt/gp/fwdecl.h index 0a42f5c..4d7afa3 100644 --- a/include/blt/gp/fwdecl.h +++ b/include/blt/gp/fwdecl.h @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include namespace blt::gp { @@ -113,6 +116,149 @@ namespace blt::gp } }; + template + class variable_bump_allocator + { + public: + explicit variable_bump_allocator(blt::size_t default_block_size = BLT_2MB_SIZE): default_block_size(default_block_size) + {} + + void* allocate(blt::size_t bytes) + { +#ifdef BLT_TRACK_ALLOCATIONS + tracker.allocate(bytes); +#endif + std::scoped_lock lock(mutex); + if (head == nullptr || head->remaining_bytes_in_block() < static_cast(bytes)) + { + push_block(bytes); + } + auto ptr = head->metadata.offset; + head->metadata.offset += bytes; + ++head->metadata.allocated_objects; + return ptr; + } + + void deallocate(void* ptr, blt::size_t bytes) + { + if (ptr == nullptr) + return; +#ifdef BLT_TRACK_ALLOCATIONS + tracker.deallocate(bytes); +#else + (void) bytes; +#endif + std::scoped_lock lock(mutex); + auto blk = to_block(ptr); + --blk->metadata.allocated_objects; + if (blk->metadata.allocated_objects == 0) + { + if (head == blk) + head = head->metadata.next; + else + { + auto prev = head; + auto next = head->metadata.next; + while (next != blk) + { + prev = next; + next = next->metadata.next; + } + prev->metadata.next = next->metadata.next; + } + deallocated_blocks.push_back(blk); + } + } + + ~variable_bump_allocator() + { + std::scoped_lock lock(mutex); + for (auto* blk : deallocated_blocks) + alloc.deallocate(blk, blk->metadata.size); + auto cur = head; + while (cur != nullptr) + { + auto* ptr = cur; + cur = cur->metadata.next; + alloc.deallocate(ptr, ptr->metadata.size); + } + head = nullptr; + } + + private: + struct block_t + { + struct block_metadata_t + { + blt::size_t size = 0; + blt::size_t allocated_objects = 0; + block_t* next = nullptr; + blt::u8* offset = nullptr; + } metadata; + blt::u8 buffer[8]{}; + + explicit block_t(blt::size_t size) + { + metadata.size = size; + reset(); + } + + void reset() + { + metadata.offset = buffer; + } + + [[nodiscard]] blt::ptrdiff_t storage_size() const noexcept + { + return static_cast(metadata.size - sizeof(typename block_t::block_metadata_t)); + } + + [[nodiscard]] blt::ptrdiff_t used_bytes_in_block() const noexcept + { + return static_cast(metadata.offset - buffer); + } + + [[nodiscard]] blt::ptrdiff_t remaining_bytes_in_block() const noexcept + { + return storage_size() - used_bytes_in_block(); + } + }; + + static inline block_t* to_block(void* p) + { + return reinterpret_cast(reinterpret_cast(p) & static_cast(~(BLT_2MB_SIZE - 1))); + } + + void push_block(blt::size_t bytes) + { + auto blk = allocate_block(bytes); + blk->metadata.next = head; + head = blk; + } + + inline block_t* allocate_block(blt::size_t bytes) + { + if (!deallocated_blocks.empty()) + { + auto blk = deallocated_blocks.back(); + blk->reset(); + deallocated_blocks.pop_back(); + return blk; + } + auto size = align_size_to(bytes + sizeof(typename block_t::block_metadata_t), default_block_size); + auto* ptr = static_cast(alloc.allocate(size, blt::huge_page_t::BLT_2MB_PAGE)); + new(ptr) block_t{size}; + return ptr; + } + + private: + block_t* head = nullptr; + std::mutex mutex; + std::vector deallocated_blocks; + Alloc alloc; + blt::size_t default_block_size; + }; + template class tracked_allocator_t { diff --git a/include/blt/gp/stack.h b/include/blt/gp/stack.h index 4a883ab..19e8489 100644 --- a/include/blt/gp/stack.h +++ b/include/blt/gp/stack.h @@ -49,7 +49,7 @@ namespace blt::gp constexpr static blt::size_t MAX_ALIGNMENT = 8; template using NO_REF_T = std::remove_cv_t>; - using Allocator = aligned_allocator; + using Allocator = variable_bump_allocator<>; public: static Allocator& get_allocator(); diff --git a/src/program.cpp b/src/program.cpp index 8481451..07f8467 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -52,7 +52,7 @@ namespace blt::gp stack_allocator::Allocator& stack_allocator::get_allocator() { - thread_local static Allocator allocator; + static Allocator allocator; return allocator; }