From 3c5c9b4a9724963700c526585ce30b2ddf597387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Leclaire-Fournier?= Date: Mon, 11 Mar 2024 19:44:38 -0400 Subject: [PATCH] allocPool: Try to avoid false sharing. A benchmark on a 50 objects size with false sharing mitigations gives these values (for the initArray() function): - With mitigations: 5508 microseconds - Without mitigations: 9075 microseconds --- allocPool.hpp | 24 +++++++++++++----------- main.cpp | 2 ++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/allocPool.hpp b/allocPool.hpp index d4ef1ba..b16674e 100644 --- a/allocPool.hpp +++ b/allocPool.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -19,10 +20,10 @@ template requires std::default_initializable && resetable class allocPool { public: - explicit allocPool(size_t defaultAllocNumbers = 1000) - : vec(defaultAllocNumbers), pivot{defaultAllocNumbers} { + explicit allocPool(size_t allocNumbers) + : vec(allocNumbers), pivot{allocNumbers} { memset(&(vec[0]), 0, sizeof(vec[0]) * vec.size()); - initArray(defaultAllocNumbers); + initArray(allocNumbers); } ~allocPool() { @@ -57,18 +58,19 @@ private: std::unordered_map positionMap; size_t pivot; - void initArray(size_t amount) { - const auto amountOfThreads{std::thread::hardware_concurrency()}; + void initArray(size_t arrSize) { + size_t amountOfThreads{std::thread::hardware_concurrency()}; assert(amountOfThreads); - const auto amountPerThread{amount / amountOfThreads}; + size_t amountPerThread{arrSize / amountOfThreads}; + size_t minObjPerThread{std::hardware_destructive_interference_size / sizeof(void *)}; std::vector threads; threads.reserve(amountOfThreads); - // Using an allocPool, we estimate that we want to allocate a lot of objects, therefore - // the amount per thread *should* be higher than a cache line. This means we should, for - // the most part, avoid false sharing. In the case that it isn't, then the total amount - // should be pretty low, therefore false sharing shouldn't matter. + // We try to avoid false sharing by defining a minimum size. + amountPerThread = minObjPerThread > amountPerThread ? minObjPerThread : amountPerThread; + amountOfThreads = arrSize / amountPerThread; + for (size_t i{}; i < amountOfThreads; i++) threads.emplace_back(&allocPool::initObjects, this, i * amountPerThread, amountPerThread); @@ -76,7 +78,7 @@ private: t.join(); // Remainder - initObjects(amount - (amount % amountOfThreads), amount % amountOfThreads); + initObjects(arrSize - (arrSize % amountOfThreads), arrSize % amountOfThreads); } void initObjects(size_t startIdx, size_t amount) { diff --git a/main.cpp b/main.cpp index 712f14f..5359a32 100644 --- a/main.cpp +++ b/main.cpp @@ -4,8 +4,10 @@ #include "tests.hpp" int main() { +#ifdef _DEBUG tests t; t.runTests(); +#endif auto startSlow{std::chrono::high_resolution_clock::now()}; stub *ptr{};