From ef7477163fe7a2bc374a74c8dd940a855e1a6e82 Mon Sep 17 00:00:00 2001 From: Hossein Moein Date: Sun, 1 Oct 2023 08:40:19 -0400 Subject: [PATCH] Everything now works with fixed size allocators --- include/DataFrame/Utils/FixedSizeAllocator.h | 42 ++++++--- test/allocator_tester.cc | 95 +++++++++++++------- 2 files changed, 89 insertions(+), 48 deletions(-) diff --git a/include/DataFrame/Utils/FixedSizeAllocator.h b/include/DataFrame/Utils/FixedSizeAllocator.h index 1bb1b5bf..c9e4fa3c 100644 --- a/include/DataFrame/Utils/FixedSizeAllocator.h +++ b/include/DataFrame/Utils/FixedSizeAllocator.h @@ -51,7 +51,7 @@ struct StaticStorage { using value_type = T; using size_type = std::size_t; - inline static constexpr size_type max_size = MAX_SIZE; + inline static constexpr size_type max_size = MAX_SIZE * sizeof(value_type); inline static constexpr bool is_static = true; StaticStorage() = default; @@ -65,7 +65,7 @@ struct StaticStorage { // Main allocation space // alignas(value_type[]) - inline static unsigned char buffer_[MAX_SIZE * sizeof(value_type)]; + inline static unsigned char buffer_[max_size]; }; // ---------------------------------------------------------------------------- @@ -76,7 +76,7 @@ struct StackStorage { using value_type = T; using size_type = std::size_t; - inline static constexpr size_type max_size = MAX_SIZE; + inline static constexpr size_type max_size = MAX_SIZE * sizeof(value_type); inline static constexpr bool is_static = false; StackStorage() = default; @@ -90,7 +90,7 @@ struct StackStorage { // Main allocation space // alignas(value_type[]) - unsigned char buffer_[MAX_SIZE * sizeof(value_type)]; + unsigned char buffer_[max_size]; }; // ---------------------------------------------------------------------------- @@ -149,7 +149,8 @@ struct BestFitAlgo : public S { // Like malloc // - pointer get_space (size_type requested_size) { + [[nodiscard]] pointer + get_space (size_type requested_size) { for (auto iter = free_blocks_start_.begin(); iter != free_blocks_start_.end(); @@ -179,7 +180,8 @@ struct BestFitAlgo : public S { // Like free // - void put_space (pointer to_be_freed, size_type) { + void + put_space (pointer to_be_freed, size_type) { auto used_iter = used_blocks_.find({ to_be_freed, 0 }); @@ -237,7 +239,7 @@ struct BestFitAlgo : public S { } // If we could not join with any other adjacent free blocks, - // process it as stand alone + // process it as a stand alone // if (! (found_tail || found_head)) { const pointer end_address = @@ -252,19 +254,21 @@ struct BestFitAlgo : public S { // used_blocks_.erase(used_iter); } - else // This is undefined behavior in delete operator - throw std::invalid_argument("BestFitAlgo::put_space()"); + // else // This is undefined behavior in delete operator + // throw std::invalid_argument("BestFitAlgo::put_space()"); } private: + // It is based on size, so it must be multi-set + // using blk_set = std::multiset; using blk_uoset = std::unordered_set; using blk_uomap = std::unordered_map; blk_set free_blocks_start_ { }; // Pointres to free block beginnings. blk_uomap free_blocks_end_ { }; // Pointres to free block ends. - blk_uoset used_blocks_ { }; // Used blocks + blk_uoset used_blocks_ { }; // Set of used blocks }; // ---------------------------------------------------------------------------- @@ -282,7 +286,7 @@ struct FirstFitStaticBase : public StaticStorage { // The bitmap to indicate which slots are in use. // - alignas(64) + alignas(value_type[]) inline static unsigned char in_use_[MAX_SIZE]; // Pointer to the first free slot. @@ -316,7 +320,7 @@ struct FirstFitStackBase : public StackStorage { // The bitmap to indicate which slots are in use. // - alignas(64) + alignas(value_type[]) unsigned char in_use_[MAX_SIZE]; // Pointer to the first free slot. @@ -342,7 +346,8 @@ struct FirstFitAlgo : public S { // Like malloc // - pointer get_space (size_type requested_size) { + [[nodiscard]] pointer + get_space (size_type requested_size) { // Pointers to the "in use" bitmap. // @@ -381,7 +386,8 @@ struct FirstFitAlgo : public S { // Like free // - void put_space (pointer to_be_freed, size_type space_size) { + void + put_space (pointer to_be_freed, size_type space_size) { // Find the start of the range. // @@ -512,18 +518,26 @@ class FixedSizeAllocator : ALGO> { // ---------------------------------------------------------------------------- +// This is slower than first-fit, but it causes a lot less fragmentations. +// template using StaticBestFitAllocator = FixedSizeAllocator; +// This is slower than first-fit, but it causes a lot less fragmentations. +// template using StackBestFitAllocator = FixedSizeAllocator; +// This is faster than best-fit, but it causes more fragmentations. +// template using StaticFirstFitAllocator = FixedSizeAllocator; +// This is faster than best-fit, but it causes more fragmentations. +// template using StackFirstFitAllocator = FixedSizeAllocator; diff --git a/test/allocator_tester.cc b/test/allocator_tester.cc index f2db869f..a816c8d8 100644 --- a/test/allocator_tester.cc +++ b/test/allocator_tester.cc @@ -28,9 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include +#include #include #include +#include #include #include @@ -241,6 +244,35 @@ static void test_first_fit_static_allocator() { my_map.insert({ i, i * 10 }); for (int i = 0; i < 1000; ++i) assert((my_map.find(i)->second == i * 10)); + + FirstFitAlgo> allocator; + std::vector> ptr_vec; + std::mt19937 gen { 98 }; + + std::srand(98); + for (std::size_t i = 0; i < 1000; ++i) { + for (std::size_t j = 0; j < 10; ++j) { + const std::size_t size = (std::rand() % 100) * sizeof(int); + const auto ptr = allocator.get_space(size); + + ptr_vec.push_back(std::make_pair(ptr, size)); + } + + std::shuffle(ptr_vec.begin(), ptr_vec.end(), gen); + + if ((i % 10) == 0) { + for (std::size_t w = 0; w < (ptr_vec.size() / 3); ++w) + allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); + ptr_vec.erase(ptr_vec.begin(), + ptr_vec.begin() + (ptr_vec.size() / 3)); + } + else { + for (std::size_t w = 0; w < (ptr_vec.size() / 2); ++w) + allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); + ptr_vec.erase(ptr_vec.begin(), + ptr_vec.begin() + (ptr_vec.size() / 2)); + } + } } // ----------------------------------------------------------------------------- @@ -327,40 +359,6 @@ static void test_first_fit_stack_allocator() { // ----------------------------------------------------------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void test_best_fit_static_allocator() { std::cout << "\nTesting StaticBestFitAllocator ..." << std::endl; @@ -439,6 +437,35 @@ static void test_best_fit_static_allocator() { my_map.insert({ i, i * 10 }); for (int i = 0; i < 1000; ++i) assert((my_map.find(i)->second == i * 10)); + + BestFitAlgo> allocator; + std::vector> ptr_vec; + std::mt19937 gen { 98 }; + + std::srand(98); + for (std::size_t i = 0; i < 10000; ++i) { + for (std::size_t j = 0; j < 100; ++j) { + const std::size_t size = (std::rand() % 100) * sizeof(int); + const auto ptr = allocator.get_space(size); + + ptr_vec.push_back(std::make_pair(ptr, size)); + } + + std::shuffle(ptr_vec.begin(), ptr_vec.end(), gen); + + if ((i % 10) == 0) { + for (std::size_t w = 0; w < (ptr_vec.size() / 3); ++w) + allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); + ptr_vec.erase(ptr_vec.begin(), + ptr_vec.begin() + (ptr_vec.size() / 3)); + } + else { + for (std::size_t w = 0; w < (ptr_vec.size() / 2); ++w) + allocator.put_space(ptr_vec[w].first, ptr_vec[w].second); + ptr_vec.erase(ptr_vec.begin(), + ptr_vec.begin() + (ptr_vec.size() / 2)); + } + } } // -----------------------------------------------------------------------------