area allocator workings (basic, needs improvement)

v1
Brett 2023-12-18 02:02:35 -05:00
parent 57be387904
commit b012b9f27c
4 changed files with 152 additions and 46 deletions

View File

@ -12,6 +12,7 @@
#include <cstring> #include <cstring>
#include "queue.h" #include "queue.h"
#include <blt/std/assert.h> #include <blt/std/assert.h>
#include <blt/std/logging.h>
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include <algorithm> #include <algorithm>
@ -506,7 +507,7 @@ namespace blt
} }
}; };
template<typename T> template<typename T, size_t BLOCK_SIZE = 8192>
class area_allocator class area_allocator
{ {
public: public:
@ -522,72 +523,94 @@ namespace blt
size_t n; size_t n;
}; };
void expand() struct block_storage
{ {
size_t new_size = m_size * 2; pointer data;
T* data = static_cast<T*>(malloc(sizeof(T) * new_size)); size_t used = 0;
if constexpr (std::is_trivially_copyable_v<T>) // TODO: b-tree?
std::memcpy(data, m_data, m_size); std::vector<pointer_view> unallocated_blocks;
else if constexpr (std::is_move_assignable_v<T> || std::is_move_constructible_v<T>) };
{
for (size_t i = 0; i < m_size; i++)
data[i] = std::move(m_data[i]);
} else if constexpr (std::is_copy_assignable_v<T> || std::is_copy_constructible_v<T>)
{
for (size_t i = 0; i < m_size; i++)
data[i] = m_data[i];
} else
{
static_assert("Unable to use this type with this allocator!");
}
free(m_data);
m_data = data;
m_size = new_size;
}
void realign() void allocate_block()
{ {
BLT_INFO("Allocating a new block of size %d", BLOCK_SIZE);
block_storage blk;
blk.data = static_cast<pointer>(malloc(sizeof(T) * BLOCK_SIZE));
blocks.push_back(blk);
} }
public: public:
area_allocator() area_allocator()
{ {
m_data = new T[m_size]; allocate_block();
} }
[[nodiscard]] pointer* allocate(size_t n) [[nodiscard]] pointer allocate(size_t n)
{ {
if (m_last + n > m_size) if (n > BLOCK_SIZE)
expand(); {
pointer loc = &m_data[m_last]; // handle cases where they want to allocate one large huge block
m_last += n; // in this case we do not care about it since the allocator is meant for small object allocations
return loc; throw std::runtime_error("Requested allocation is too large!");
}
// TODO: something better
if (blocks.back().used + n > BLOCK_SIZE)
{
BLT_TRACE("Moving to a new block");
allocate_block();
}
auto& current_block = blocks.back();
auto* ptr = &blocks.back().data[current_block.used];
if constexpr (std::is_default_constructible_v<T> && !std::is_trivially_default_constructible_v<T>)
{
for (size_t i = 0; i < n; i++)
new(&ptr[i]) T();
}
current_block.used += n;
return ptr;
} }
void deallocate(pointer* p, size_t n) noexcept void deallocate(pointer p, size_t n) noexcept
{ {
deallocated_blocks.push({p, n}); for (size_t i = 0; i < n; i++)
m_deallocated += n; p[i].~T();
// TODO: magic number for (auto& blk : blocks)
if (static_cast<double>(m_deallocated) / static_cast<double>(m_last) > 0.25) {
realign(); if (p >= blk.data && p <= (blk.data + BLOCK_SIZE))
{
blk.unallocated_blocks.push_back({p, n});
break;
}
}
} }
~area_allocator() ~area_allocator()
{ {
delete[] m_data; for (auto& blk : blocks)
{
// for (size_t i = 0; i < blk.used; i++)
// {
// bool alreadyDeallocated = false;
// for (const auto& dealoc : blk.unallocated_blocks)
// {
// auto pos = (blk.data + i);
// if (pos >= dealoc.p && pos <= (dealoc.p + dealoc.n))
// {
// alreadyDeallocated = true;
// break;
// }
// }
// if (!alreadyDeallocated)
// blk.data[i].~T();
// }
// it is UB to not deallocate allocated memory. Get fucked.
free(blk.data);
}
} }
private: private:
// current size of the data std::vector<block_storage> blocks;
size_t m_size = 1;
// last allocated location
size_t m_last = 0;
// how many values have been deallocated
size_t m_deallocated = 0;
T* m_data = nullptr;
blt::flat_queue<pointer_view> deallocated_blocks;
}; };
} }

View File

@ -28,12 +28,15 @@ namespace blt::test::memory
void static_vector_test(); void static_vector_test();
void test();
static inline void run() static inline void run()
{ {
copy(); copy();
move(); move();
access(); access();
static_vector_test(); static_vector_test();
test();
} }
} }

View File

@ -69,6 +69,12 @@ namespace blt
blt_linked_stack.push(random_data[i]); blt_linked_stack.push(random_data[i]);
BLT_END_INTERVAL(insertProfile, "blt::linked_stack"); BLT_END_INTERVAL(insertProfile, "blt::linked_stack");
std::vector<int> vector_stack;
BLT_START_INTERVAL(insertProfile, "std::vector");
for (size_t i = 0; i < size; i++)
vector_stack.push_back(random_data[i]);
BLT_END_INTERVAL(insertProfile, "std::vector");
BLT_START_INTERVAL(readProfile, "std::stack"); BLT_START_INTERVAL(readProfile, "std::stack");
for (size_t i = 0; i < size; i++) for (size_t i = 0; i < size; i++)
{ {
@ -93,6 +99,14 @@ namespace blt
} }
BLT_END_INTERVAL(readProfile, "blt::linked_stack"); BLT_END_INTERVAL(readProfile, "blt::linked_stack");
BLT_START_INTERVAL(readProfile, "std::vector");
for (size_t i = 0; i < size; i++)
{
blt::black_box(vector_stack.back());
vector_stack.pop_back();
}
BLT_END_INTERVAL(readProfile, "std::vector");
BLT_PRINT_PROFILE(insertProfile); BLT_PRINT_PROFILE(insertProfile);
BLT_PRINT_PROFILE(readProfile); BLT_PRINT_PROFILE(readProfile);
} }

View File

@ -21,6 +21,7 @@
#include <blt/std/assert.h> #include <blt/std/assert.h>
#include <blt/std/random.h> #include <blt/std/random.h>
#include <type_traits> #include <type_traits>
#include "blt/std/utility.h"
template<typename T> template<typename T>
blt::scoped_buffer<T> create_scoped_buffer(size_t size) blt::scoped_buffer<T> create_scoped_buffer(size_t size)
@ -134,3 +135,68 @@ void blt::test::memory::static_vector_test()
BLT_DEBUG_STREAM << v << ' '; BLT_DEBUG_STREAM << v << ' ';
BLT_DEBUG_STREAM << '\n'; BLT_DEBUG_STREAM << '\n';
} }
struct fucked_type1
{
private:
int T = 0;
public:
fucked_type1() = default;
};
struct fucked_type2
{
public:
int T = 0;
public:
fucked_type2()
{
T = 50;
BLT_DEBUG("I HAVE BEEN CONSTRUCTED");
}
~fucked_type2()
{
BLT_DEBUG("I HAVE BEEN DESTRUCTED!");
}
};
void blt::test::memory::test()
{
area_allocator<fucked_type2, 20> int_test{};
//auto arr = int_test.allocate(10);
auto arr2 = int_test.allocate(15);
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
blt::black_box(int_test.allocate(1));
//blt::black_box(arr4);
BLT_INFO("CUM");
// arr3 = int_test.allocate(2);
// blt::black_box(arr3);
// arr3 = int_test.allocate(5);
// blt::black_box(arr3);
// arr3 = int_test.allocate(10);
// blt::black_box(arr3);
//auto arr3 = int_test.allocate(20);
//std::memset(arr, 0, 10);
//std::memset(arr2, 0, 15);
//std::memset(arr3, 0, 20);
for (int i = 0; i < 15; i++)
{
BLT_TRACE_STREAM << arr2[i].T << ' ';
}
BLT_TRACE_STREAM << "\n";
int_test.deallocate(arr2, 15);
BLT_INFO("-----------------");
}