allocPool: Fix threading issue and add benchmark.

This commit is contained in:
Timothée Leclaire-Fournier 2024-03-01 16:30:51 -05:00
parent dead668fb7
commit 6cd26d5ee9
6 changed files with 72 additions and 3 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea/*
cmake-build-debug/*

View File

@ -11,4 +11,20 @@ objects before giving them to another caller.
This pool uses a hashmap and a pivot to make returnPtr(ptr) extremely fast.
It will automatically grow when the max capacity is reached, though there will
be a performance penalty.
be a performance penalty.
## Performance
With a simple stub class and a pool of 10000 objects, using the pool to take a pointer
and give it back takes 3 ms vs 19 ms when allocating and deallocating by hand.
```
class stub {
public:
stub() {
for (int j{}; j < 1000; j++) { i++; }
};
void reset() {}
private:
int i = 15;
};
```

View File

@ -47,6 +47,7 @@ public:
private:
std::vector<T *> vec;
std::mutex positionMapMutex;
std::unordered_map<T *, size_t> positionMap;
size_t pivot;
@ -59,7 +60,7 @@ private:
threads.reserve(amountOfThreads);
for (size_t i{}; i < amountOfThreads; i++)
threads.emplace_back(&allocPool::initObjects, this, i, amountPerThreads);
threads.emplace_back(&allocPool::initObjects, this, i * amountPerThreads, amountPerThreads);
for (auto &t: threads)
t.join();
@ -72,6 +73,9 @@ private:
for (size_t i{}; i < amount; i++) {
// TODO: Be more cache friendly by making a vector per thread, then doing memcpy into the original vector.
vec[startIdx + i] = new T;
}
std::lock_guard<std::mutex> guard(positionMapMutex);
for (size_t i{}; i < amount; i++) {
positionMap[vec[startIdx + i]] = i;
}
}

View File

@ -1,7 +1,39 @@
#include <chrono>
#include <iostream>
#include "tests.hpp"
int main() {
tests t;
t.runTests();
auto startSlow{std::chrono::high_resolution_clock::now()};
stub *ptr{};
for (size_t i{}; i < 10000; i++) {
ptr = new stub();
delete ptr;
}
auto endSlow{std::chrono::high_resolution_clock::now()};
std::cout << "Time (milliseconds) required for allocations without pool: " <<
std::chrono::duration_cast<std::chrono::milliseconds>(endSlow - startSlow).count() << "\n";
auto startAlloc{std::chrono::high_resolution_clock::now()};
allocPool<stub> a(10000);
auto endAlloc{std::chrono::high_resolution_clock::now()};
auto startFast{std::chrono::high_resolution_clock::now()};
for (size_t i{}; i < 10000; i++) {
ptr = a.getPtr();
a.returnPtr(ptr);
}
auto endFast{std::chrono::high_resolution_clock::now()};
std::cout << "Time (milliseconds) required for allocations with pool: " <<
std::chrono::duration_cast<std::chrono::milliseconds>(endFast - startFast).count() << "\n";
std::cout << "Time (milliseconds) required for real allocations when constructing pool: " <<
std::chrono::duration_cast<std::chrono::milliseconds>(endAlloc - startAlloc).count() << "\n";
return 0;
}

View File

@ -24,4 +24,16 @@ ADD_TEST(allocPoolSimple) {
pool.returnPtr(var1);
pool.returnPtr(var4);
pool.returnPtr(var3);
}
ADD_TEST(allocPoolSimple2) {
allocPool<stub> pool(10);
auto *var1{pool.getPtr()};
auto *var2{pool.getPtr()};
auto *var3{pool.getPtr()};
pool.returnPtr(var2);
auto *var4{pool.getPtr()};
pool.returnPtr(var1);
pool.returnPtr(var4);
pool.returnPtr(var3);
}

View File

@ -32,8 +32,11 @@ public:
class stub {
public:
stub() = default;
stub() {
for (int j{}; j < 1000; j++) { i++; }
};
void reset() {}
private:
int i = 15;
};