diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 7440170..b69cc57 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -5,7 +5,7 @@ add_compile_definitions(__IPC_LIBRARY__) if(MSVC) add_compile_options("/std:c++17") else() - add_compile_options("-std=gnu++1z") + add_compile_options("-std=gnu++1z -O2") endif() include_directories("../include") diff --git a/build/test.pro b/build/test.pro index 5fc56f4..111e347 100644 --- a/build/test.pro +++ b/build/test.pro @@ -24,7 +24,8 @@ SOURCES += \ ../test/main.cpp \ ../test/test_shm.cpp \ ../test/test_circ.cpp \ - ../test/test_ipc.cpp + ../test/test_ipc.cpp \ + ../test/test_mem.cpp LIBS += \ -L$${DESTDIR} -lipc diff --git a/src/memory/resource.hpp b/src/memory/resource.hpp index 152bcb9..3de049b 100644 --- a/src/memory/resource.hpp +++ b/src/memory/resource.hpp @@ -16,14 +16,14 @@ namespace mem { namespace detail { template -constexpr decltype(auto) switch_constexpr(std::size_t /*i*/, std::index_sequence<>, F&& /*f*/, D&& def) { +constexpr decltype(auto) static_switch(std::size_t /*i*/, std::index_sequence<>, F&& /*f*/, D&& def) { return def(); } template -constexpr decltype(auto) switch_constexpr(std::size_t i, std::index_sequence, F&& f, D&& def) { +constexpr decltype(auto) static_switch(std::size_t i, std::index_sequence, F&& f, D&& def) { return (i == N) ? f(std::integral_constant{}) : - switch_constexpr(i, std::index_sequence{}, f, def); + static_switch(i, std::index_sequence{}, f, def); } } // namespace detail @@ -40,7 +40,7 @@ private: static decltype(auto) choose(std::size_t size, F&& f) { enum : std::size_t { base_size = sizeof(void*) }; size = ((size - 1) & (~(base_size - 1))) + base_size; - return detail::switch_constexpr(size, std::index_sequence< + return detail::static_switch(size, std::index_sequence< base_size , base_size * 2 , base_size * 3 , base_size * 4 , base_size * 5 , base_size * 6 , diff --git a/test/test.h b/test/test.h index 6e2b398..ff71177 100644 --- a/test/test.h +++ b/test/test.h @@ -40,11 +40,16 @@ struct test_stopwatch { } } + template void print_elapsed(int N, int M, int Loops) { auto ts = sw_.elapsed(); std::cout << "[" << N << ":" << M << ", " << Loops << "] " << "performance: " << (ts / 1000.0) << " ms, " - << (double(ts) / double(Loops * N)) << " us/d" << std::endl; + << (double(ts) / double(Factor ? (Loops * Factor) : (Loops * N))) << " us/d" << std::endl; + } + + void print_elapsed(int N, int M, int Loops) { + print_elapsed<0>(N, M, Loops); } }; diff --git a/test/test_ipc.cpp b/test/test_ipc.cpp index 7b81774..21c27c6 100644 --- a/test/test_ipc.cpp +++ b/test/test_ipc.cpp @@ -462,7 +462,7 @@ void Unit::test_channel() { std::thread t2 {[&] { ipc::channel cc { "my-ipc-channel" }; cc.wait_for_recv(1); - for (std::size_t i = 0; i < (std::min)(100, LoopCount); ++i) { + for (std::size_t i = 0; i < static_cast((std::min)(100, LoopCount)); ++i) { std::cout << "sending: " << i << "-[" << datas__[i].size() << "]" << std::endl; cc.send(datas__[i]); } diff --git a/test/test_mem.cpp b/test/test_mem.cpp new file mode 100644 index 0000000..5625b34 --- /dev/null +++ b/test/test_mem.cpp @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#include "random.hpp" + +#include "memory/resource.hpp" +#include "test.h" + +namespace { + +class Unit : public TestSuite { + Q_OBJECT + + const char* name() const { + return "test_mem"; + } + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void test_alloc(); +} unit__; + +#include "test_mem.moc" + +constexpr int DataMin = sizeof(void*); +constexpr int DataMax = sizeof(void*) * 16; +constexpr int LoopCount = 1000000; + +std::vector sizes__; + +template +struct alloc_ix_t { + static std::vector ix_[2]; + static bool inited_; +}; + +template +std::vector alloc_ix_t::ix_[2] = { std::vector(LoopCount), std::vector(LoopCount) }; +template +bool alloc_ix_t::inited_ = false; + +struct alloc_random : alloc_ix_t { + alloc_random() { + if (inited_) return; + inited_ = true; + capo::random<> rdm_index(0, LoopCount - 1); + for (int i = 0; i < LoopCount; ++i) { + ix_[0][static_cast(i)] = + ix_[1][static_cast(i)] = rdm_index(); + } + } +}; + +struct alloc_LIFO : alloc_ix_t { + alloc_LIFO() { + if (inited_) return; + inited_ = true; + for (int i = 0, n = LoopCount - 1; i < LoopCount; ++i, --n) { + ix_[0][static_cast(i)] = + ix_[1][static_cast(n)] = i; + } + } +}; + +struct alloc_FIFO : alloc_ix_t { + alloc_FIFO() { + if (inited_) return; + inited_ = true; + for (int i = 0; i < LoopCount; ++i) { + ix_[0][static_cast(i)] = + ix_[1][static_cast(i)] = i; + } + } +}; + +void Unit::initTestCase() { + TestSuite::initTestCase(); + + capo::random<> rdm { DataMin, DataMax }; + for (int i = 0; i < LoopCount; ++i) { + sizes__.emplace_back(static_cast(rdm())); + } + +} + +void Unit::cleanupTestCase() { + sizes__.clear(); +} + +template +void benchmark_alloc() { + std::cout << std::endl + << "[Threads: " << ThreadsN << ", Mode: " << type_name() << "] " + << type_name() << std::endl; + + 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] { + sw.start(); + for (std::size_t x = 0; x < 2; ++x) { + for(std::size_t n = 0; n < LoopCount; ++n) { + int m = mode.ix_[x][n]; + void* (& p) = ptrs[pid][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 == ThreadsN) { + sw.print_elapsed<1>(DataMin, DataMax, LoopCount); + } + }}; + ++pid; + } + sw.start(); + + for (auto& w : works) w.join(); +} + +template +struct test_performance { + static void start() { + test_performance::start(); + benchmark_alloc(); + } +}; + +template +struct test_performance { + static void start() { + benchmark_alloc(); + } +}; + +void Unit::test_alloc() { + // malloc + test_performance::start(); + test_performance::start(); + test_performance::start(); + // pool-alloc + test_performance::start(); + test_performance::start(); + test_performance::start(); +} + +} // internal-linkage