allocPool: Add option to disable the false sharing mitigations.
This commit is contained in:
parent
7f58269866
commit
fd8203400c
20
README.md
20
README.md
@ -6,16 +6,22 @@ constructor (with threads) then offers you two functions: `getPtr()` and `return
|
|||||||
|
|
||||||
Using C++ concepts, we can use templates and require the class given to have a
|
Using C++ concepts, we can use templates and require the class given to have a
|
||||||
default constructor and to have a `.reset()` function. It will be used to clean the
|
default constructor and to have a `.reset()` function. It will be used to clean the
|
||||||
objects before giving them to another caller.
|
objects before giving them to another caller instead of reallocating.
|
||||||
|
|
||||||
We avoid false sharing by keeping a high amount of work per thread. This should
|
We avoid false sharing by keeping a high amount of work per thread. This should
|
||||||
lead to cache lines not being shared between threads. While this pool uses a hashmap
|
lead to cache lines not being shared between threads. In the advent that cache
|
||||||
and a pivot to make `returnPtr(ptr)` extremely fast, the construction's main bottleneck is
|
lines would overlap, we use a smaller amount of threads with a bit more work
|
||||||
in the locking and unlocking of the hashmap's mutex. We need to do this since we cannot
|
per thread. This option is enabled with the `bool enableFalseSharingMitigations`
|
||||||
write in a `std::unordered_map` at different hashes concurrently.
|
parameter in the constructor. It is on by default and can be disabled in the advent
|
||||||
|
that you very big objects where writing pointers in the `std::vector` will not be the
|
||||||
|
bottleneck.
|
||||||
|
|
||||||
It will automatically grow when the max capacity is reached, though there will
|
While this pool uses a hashmap and a pivot to make `returnPtr(ptr)` extremely fast,
|
||||||
be a performance penalty.
|
when saving the pointers, the main bottleneck is in the locking and unlocking of the
|
||||||
|
hashmap's mutex. We need to do this since we cannot write in a `std::unordered_map`
|
||||||
|
at different hashes concurrently.
|
||||||
|
|
||||||
|
It will automatically grow to twice its size when the max capacity is reached.
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
With a simple stub class and a pool of 10000 objects, using the pool to take a pointer
|
With a simple stub class and a pool of 10000 objects, using the pool to take a pointer
|
||||||
|
@ -20,8 +20,8 @@ template<class T>
|
|||||||
requires std::default_initializable<T> && resetable<T>
|
requires std::default_initializable<T> && resetable<T>
|
||||||
class allocPool {
|
class allocPool {
|
||||||
public:
|
public:
|
||||||
explicit allocPool(size_t allocNumbers)
|
explicit allocPool(size_t allocNumbers, bool enableFalseSharingMitigations = true)
|
||||||
: vec(allocNumbers), pivot{allocNumbers} {
|
: vec(allocNumbers), pivot{allocNumbers}, falseSharingMitigations{enableFalseSharingMitigations} {
|
||||||
memset(&(vec[0]), 0, sizeof(vec[0]) * vec.size());
|
memset(&(vec[0]), 0, sizeof(vec[0]) * vec.size());
|
||||||
initArray(allocNumbers);
|
initArray(allocNumbers);
|
||||||
}
|
}
|
||||||
@ -57,6 +57,7 @@ private:
|
|||||||
std::mutex positionMapMutex;
|
std::mutex positionMapMutex;
|
||||||
std::unordered_map<T *, size_t> positionMap;
|
std::unordered_map<T *, size_t> positionMap;
|
||||||
size_t pivot;
|
size_t pivot;
|
||||||
|
bool falseSharingMitigations;
|
||||||
|
|
||||||
void initArray(size_t arrSize) {
|
void initArray(size_t arrSize) {
|
||||||
size_t amountOfThreads{std::thread::hardware_concurrency()};
|
size_t amountOfThreads{std::thread::hardware_concurrency()};
|
||||||
@ -68,8 +69,10 @@ private:
|
|||||||
threads.reserve(amountOfThreads);
|
threads.reserve(amountOfThreads);
|
||||||
|
|
||||||
// We try to avoid false sharing by defining a minimum size.
|
// We try to avoid false sharing by defining a minimum size.
|
||||||
|
if (falseSharingMitigations) {
|
||||||
amountPerThread = minObjPerThread > amountPerThread ? minObjPerThread : amountPerThread;
|
amountPerThread = minObjPerThread > amountPerThread ? minObjPerThread : amountPerThread;
|
||||||
amountOfThreads = arrSize / amountPerThread;
|
amountOfThreads = arrSize / amountPerThread;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i{}; i < amountOfThreads; i++)
|
for (size_t i{}; i < amountOfThreads; i++)
|
||||||
threads.emplace_back(&allocPool::initObjects, this, i * amountPerThread, amountPerThread);
|
threads.emplace_back(&allocPool::initObjects, this, i * amountPerThread, amountPerThread);
|
||||||
|
Loading…
Reference in New Issue
Block a user