Added test and forced initialization of backend when using custom Pool.
This commit is contained in:
@@ -39,19 +39,53 @@ namespace snmalloc
|
||||
/**
|
||||
* Class used to instantiate a global non-allocator PoolState.
|
||||
*/
|
||||
template<typename T>
|
||||
template<typename T, typename SharedStateHandle>
|
||||
class SingletonPoolState
|
||||
{
|
||||
static inline PoolState<T> state;
|
||||
static thread_local inline bool initialized;
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` implements `ensure_init`. Calls it
|
||||
* if it exists.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH static auto call_ensure_init(SharedStateHandle*, int)
|
||||
-> decltype(SharedStateHandle::ensure_init())
|
||||
{
|
||||
SharedStateHandle::ensure_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* SFINAE helper. Matched only if `T` does not implement `ensure_init`.
|
||||
* Does nothing if called.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH static auto call_ensure_init(SharedStateHandle*, long) {}
|
||||
|
||||
/**
|
||||
* Call `SharedStateHandle::ensure_init()` if it is implemented, do nothing
|
||||
* otherwise.
|
||||
*/
|
||||
SNMALLOC_FAST_PATH static void ensure_init()
|
||||
{
|
||||
call_ensure_init(nullptr, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
static PoolState<T>& pool()
|
||||
SNMALLOC_FAST_PATH static PoolState<T>& pool()
|
||||
{
|
||||
if (unlikely(!initialized))
|
||||
{
|
||||
ensure_init();
|
||||
initialized = true;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename SharedStateHandle, PoolState<T>& get_state()>
|
||||
template<
|
||||
typename T,
|
||||
typename SharedStateHandle,
|
||||
PoolState<T>& get_state() = SingletonPoolState<T, SharedStateHandle>::pool>
|
||||
class Pool
|
||||
{
|
||||
public:
|
||||
|
||||
117
src/test/func/pool/pool.cc
Normal file
117
src/test/func/pool/pool.cc
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <snmalloc.h>
|
||||
#include <test/opt.h>
|
||||
#include <test/setup.h>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace snmalloc;
|
||||
|
||||
struct PoolAEntry : Pooled<PoolAEntry>
|
||||
{
|
||||
size_t field;
|
||||
|
||||
PoolAEntry() : field(1){};
|
||||
};
|
||||
|
||||
using PoolA = Pool<PoolAEntry, Alloc::StateHandle>;
|
||||
|
||||
struct PoolBEntry : Pooled<PoolBEntry>
|
||||
{
|
||||
size_t field;
|
||||
|
||||
PoolBEntry() : field(0){};
|
||||
PoolBEntry(size_t f) : field(f){};
|
||||
};
|
||||
|
||||
using PoolB = Pool<PoolBEntry, Alloc::StateHandle>;
|
||||
|
||||
void test_alloc()
|
||||
{
|
||||
auto ptr = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr != nullptr);
|
||||
// Pool allocations should not be visible to debug_check_empty.
|
||||
snmalloc::debug_check_empty<Alloc::StateHandle>();
|
||||
}
|
||||
|
||||
void test_constructor()
|
||||
{
|
||||
auto ptr1 = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr1 != nullptr);
|
||||
SNMALLOC_CHECK(ptr1->field == 1);
|
||||
|
||||
auto ptr2 = PoolB::acquire();
|
||||
SNMALLOC_CHECK(ptr2 != nullptr);
|
||||
SNMALLOC_CHECK(ptr2->field == 0);
|
||||
|
||||
auto ptr3 = PoolB::acquire(1);
|
||||
SNMALLOC_CHECK(ptr3 != nullptr);
|
||||
SNMALLOC_CHECK(ptr3->field == 1);
|
||||
}
|
||||
|
||||
void test_alloc_many()
|
||||
{
|
||||
constexpr size_t count = 16'000'000 / MIN_CHUNK_SIZE;
|
||||
|
||||
std::unordered_set<PoolAEntry*> allocated;
|
||||
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
auto ptr = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr != nullptr);
|
||||
allocated.insert(ptr);
|
||||
}
|
||||
|
||||
for (auto ptr : allocated)
|
||||
{
|
||||
PoolA::release(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void test_alloc_dealloc()
|
||||
{
|
||||
auto ptr = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr != nullptr);
|
||||
PoolA::release(ptr);
|
||||
}
|
||||
|
||||
void test_double_alloc()
|
||||
{
|
||||
auto ptr1 = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr1 != nullptr);
|
||||
auto ptr2 = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr2 != nullptr);
|
||||
SNMALLOC_CHECK(ptr1 != ptr2);
|
||||
PoolA::release(ptr2);
|
||||
auto ptr3 = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr2 == ptr3);
|
||||
}
|
||||
|
||||
void test_different_alloc()
|
||||
{
|
||||
auto ptr1 = PoolA::acquire();
|
||||
SNMALLOC_CHECK(ptr1 != nullptr);
|
||||
PoolA::release(ptr1);
|
||||
auto ptr2 = PoolB::acquire();
|
||||
SNMALLOC_CHECK(ptr2 != nullptr);
|
||||
SNMALLOC_CHECK(static_cast<void*>(ptr1) != static_cast<void*>(ptr2));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
setup();
|
||||
#ifdef USE_SYSTEMATIC_TESTING
|
||||
opt::Opt opt(argc, argv);
|
||||
size_t seed = opt.is<size_t>("--seed", 0);
|
||||
Virtual::systematic_bump_ptr() += seed << 17;
|
||||
#else
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
#endif
|
||||
|
||||
test_alloc();
|
||||
test_constructor();
|
||||
test_alloc_many();
|
||||
test_alloc_dealloc();
|
||||
test_double_alloc();
|
||||
test_different_alloc();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user