diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6cbb503 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/* +cmake-build-debug/* diff --git a/README.md b/README.md index 1b8bc33..355c061 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file +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; +}; +``` \ No newline at end of file diff --git a/allocPool.hpp b/allocPool.hpp index 0c22a35..5f1a090 100644 --- a/allocPool.hpp +++ b/allocPool.hpp @@ -47,6 +47,7 @@ public: private: std::vector vec; + std::mutex positionMapMutex; std::unordered_map 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 guard(positionMapMutex); + for (size_t i{}; i < amount; i++) { positionMap[vec[startIdx + i]] = i; } } diff --git a/main.cpp b/main.cpp index e709d80..1d8375e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,39 @@ +#include +#include + #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(endSlow - startSlow).count() << "\n"; + + auto startAlloc{std::chrono::high_resolution_clock::now()}; + allocPool 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(endFast - startFast).count() << "\n"; + + std::cout << "Time (milliseconds) required for real allocations when constructing pool: " << + std::chrono::duration_cast(endAlloc - startAlloc).count() << "\n"; + return 0; } diff --git a/tests.cpp b/tests.cpp index 7f774ec..3d0e0c3 100644 --- a/tests.cpp +++ b/tests.cpp @@ -24,4 +24,16 @@ ADD_TEST(allocPoolSimple) { pool.returnPtr(var1); pool.returnPtr(var4); pool.returnPtr(var3); +} + +ADD_TEST(allocPoolSimple2) { + allocPool 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); } \ No newline at end of file diff --git a/tests.hpp b/tests.hpp index a774435..517e8ce 100644 --- a/tests.hpp +++ b/tests.hpp @@ -32,8 +32,11 @@ public: class stub { public: - stub() = default; + stub() { + for (int j{}; j < 1000; j++) { i++; } + }; void reset() {} + private: int i = 15; }; \ No newline at end of file