#include #include #include #include #include #include "capo/random.hpp" #include "memory/resource.h" #include "pool_alloc.h" // #include "gperftools/tcmalloc.h" #include "test.h" namespace { class Unit : public TestSuite { Q_OBJECT const char* name() const { return "test_mem"; } private slots: void initTestCase(); void test_static_alloc(); void test_pool_alloc(); void test_tc_alloc(); }; // } unit__; #include "test_mem.moc" constexpr int DataMin = 4; constexpr int DataMax = 256; constexpr int LoopCount = 4194304; // constexpr int DataMin = 256; // constexpr int DataMax = 512; // constexpr int LoopCount = 2097152; std::vector sizes__; template struct alloc_ix_t { static std::vector ix_; static bool inited_; alloc_ix_t() { if (inited_) return; inited_ = true; M::init(ix_); } int index(std::size_t /*pid*/, std::size_t /*k*/, std::size_t n) { return ix_[n]; } }; template std::vector alloc_ix_t::ix_(LoopCount); template bool alloc_ix_t::inited_ = false; template struct alloc_FIFO : alloc_ix_t> { static void init(std::vector& ix) { for (int i = 0; i < LoopCount; ++i) { ix[static_cast(i)] = i; } } }; template struct alloc_LIFO : alloc_ix_t> { static void init(std::vector& ix) { for (int i = 0; i < LoopCount; ++i) { ix[static_cast(i)] = i; } } int index(std::size_t pid, std::size_t k, std::size_t n) { constexpr static int CacheSize = LoopCount / N; if (k) { return this->ix_[(CacheSize * (2 * pid + 1)) - 1 - n]; } else return this->ix_[n]; } }; template struct alloc_random : alloc_ix_t> { static void init(std::vector& ix) { capo::random<> rdm_index(0, LoopCount - 1); for (int i = 0; i < LoopCount; ++i) { ix[static_cast(i)] = rdm_index(); } } }; void Unit::initTestCase() { TestSuite::initTestCase(); capo::random<> rdm { DataMin, DataMax }; for (int i = 0; i < LoopCount; ++i) { sizes__.emplace_back(static_cast(rdm())); } } template void benchmark_alloc() { std::cout << std::endl << "[Threads: " << ThreadsN << "] " << type_name() << std::endl; constexpr static int CacheSize = LoopCount / ThreadsN; std::atomic_int fini { 0 }; test_stopwatch sw; std::thread works[ThreadsN]; int pid = 0; for (auto& w : works) { w = std::thread {[&, pid] { sw.start(); for (std::size_t k = 0; k < 100; ++k) for (int n = (CacheSize * pid); n < (CacheSize * (pid + 1)); ++n) { std::size_t s = sizes__[n]; AllocT::free(AllocT::alloc(s), s); } if ((fini.fetch_add(1, std::memory_order_relaxed) + 1) == ThreadsN) { sw.print_elapsed<1, std::chrono::nanoseconds>(DataMin, DataMax, LoopCount * 100, " ns/d"); } }}; ++pid; } for (auto& w : works) w.join(); } template class ModeT, int ThreadsN> void benchmark_alloc() { std::cout << std::endl << "[Threads: " << ThreadsN << ", Mode: " << type_name>() << "] " << type_name() << std::endl; constexpr static int CacheSize = LoopCount / ThreadsN; std::vector ptrs[ThreadsN]; for (auto& vec : ptrs) { vec.resize(LoopCount); } ModeT mode; std::atomic_int fini { 0 }; test_stopwatch sw; std::thread works[ThreadsN]; int pid = 0; for (auto& w : works) { w = std::thread {[&, pid] { auto& vec = ptrs[pid]; sw.start(); for (std::size_t k = 0; k < 2; ++k) for (int n = (CacheSize * pid); n < (CacheSize * (pid + 1)); ++n) { int m = mode.index(pid, k, n); void*& p = vec[static_cast(m)]; std::size_t s = sizes__[static_cast(m)]; if (p == nullptr) { p = AllocT::alloc(s); } else { AllocT::free(p, s); p = nullptr; } } if ((fini.fetch_add(1, std::memory_order_relaxed) + 1) == ThreadsN) { sw.print_elapsed<1>(DataMin, DataMax, LoopCount); } }}; ++pid; } for (auto& w : works) w.join(); } template class ModeT, int ThreadsN> struct test_performance { static void start() { test_performance::start(); benchmark_alloc(); } }; template class ModeT> struct test_performance { static void start() { benchmark_alloc(); } }; template struct dummy; template struct test_performance { static void start() { test_performance::start(); benchmark_alloc(); } }; template struct test_performance { static void start() { benchmark_alloc(); } }; // class tc_alloc { // public: // static void clear() {} // static void* alloc(std::size_t size) { // return size ? tc_malloc(size) : nullptr; // } // static void free(void* p, std::size_t size) { // tc_free_sized(p, size); // } // }; void Unit::test_static_alloc() { // test_performance::start(); // test_performance::start(); // test_performance::start(); // test_performance::start(); } void Unit::test_pool_alloc() { test_performance::start(); test_performance::start(); test_performance::start(); test_performance::start(); test_performance::start(); test_performance::start(); } void Unit::test_tc_alloc() { // test_performance::start(); // test_performance::start(); // test_performance::start(); // test_performance::start(); } } // internal-linkage