From 98ee5fd73db580a2d2906de366fd8677420b465d Mon Sep 17 00:00:00 2001 From: Sara Gerretsen Date: Mon, 22 Sep 2025 23:13:19 +0200 Subject: [PATCH] feat: fixed incorrect behaviour on simulation and added benchmarking code --- src/simulation.cpp | 96 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/src/simulation.cpp b/src/simulation.cpp index b324acb..a5efad8 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -1,4 +1,5 @@ #include "simulation.h" +#include "SDL3/SDL_timer.h" #include "input.h" #include "thread_pool.h" #include @@ -77,10 +78,15 @@ static size_t CountNeighbors(Cell const &cell) { static std::mutex underpopulatedMutex, overpopulatedMutex, bornMutex; -static void FindOverpopulated() { +static void FindOverpopulated(size_t segment, size_t length) { overpopulatedMutex.lock(); - overpopulated.clear(); - std::ranges::copy_if(living, std::back_inserter(overpopulated), + std::set::iterator begin{ living.begin() }; + std::set::iterator end{ living.begin() }; + + std::advance(begin, segment * length); + std::advance(end, segment * length + length); + + std::copy_if(begin, end, std::back_inserter(overpopulated), [&](Cell const &c) -> bool { size_t const neighbors{ CountNeighbors(c) }; return neighbors > 3; @@ -88,10 +94,16 @@ static void FindOverpopulated() { overpopulatedMutex.unlock(); } -static void FindUnderpopulated() { +static void FindUnderpopulated(size_t segment, size_t length) { + uint64_t ns{ SDL_GetTicksNS() }; underpopulatedMutex.lock(); - underpopulated.clear(); - std::ranges::copy_if(living, std::back_inserter(underpopulated), + std::set::iterator begin{ living.begin() }; + std::set::iterator end{ living.begin() }; + + std::advance(begin, segment * length); + std::advance(end, segment * length + length); + + std::copy_if(begin, end, std::back_inserter(underpopulated), [&](Cell const &c) -> bool { size_t const neighbors{ CountNeighbors(c) }; return neighbors < 2; @@ -99,11 +111,17 @@ static void FindUnderpopulated() { underpopulatedMutex.unlock(); } -static void FindBorn() { +static void FindBorn(size_t segment, size_t length) { + uint64_t ns{ SDL_GetTicksNS() }; bornMutex.lock(); - born.clear(); - for (Cell const &cell : living) { - std::vector neighbors{ NeighborSet(cell) }; + std::set::iterator itr{ living.begin() }; + std::set::iterator end{ living.begin() }; + + std::advance(itr, segment * length); + std::advance(end, segment * length + length); + + for (;itr != end; ++itr) { + std::vector neighbors{ NeighborSet(*itr) }; std::ranges::copy_if(neighbors, std::back_inserter(born), [&](Cell const &c) -> bool { size_t const neighbors{ CountNeighbors(c) }; @@ -113,20 +131,43 @@ static void FindBorn() { bornMutex.unlock(); } +#define MULTITHREADING 0 +static uint64_t generationTime{ 0 }; +static bool logGenerationTime{ false }; + static void PopulateChanges() { -#if 1 - threading::tasks.ScheduleTask(&FindOverpopulated); - threading::tasks.ScheduleTask(&FindUnderpopulated); - threading::tasks.ScheduleTask(&FindBorn); + generationTime = SDL_GetTicksNS(); + logGenerationTime = true; +#if MULTITHREADING + constexpr size_t split{ 2 }; + size_t const seg_length{ living.size() / split }; + for (size_t i{ 0 }; i < split; ++i) { + threading::tasks.ScheduleTask(std::bind(FindOverpopulated, i, seg_length)); + threading::tasks.ScheduleTask(std::bind(FindUnderpopulated, i, seg_length)); + threading::tasks.ScheduleTask(std::bind(FindBorn, i, seg_length)); + } #else - FindOverpopulated(); - FindUnderpopulated(); - FindBorn(); + FindOverpopulated(0, living.size()); + FindUnderpopulated(0, living.size()); + FindBorn(0, living.size()); #endif } void InitializeRandom(size_t livingChance, int64_t fillArea) { + underpopulatedMutex.lock(); + underpopulated.clear(); + underpopulatedMutex.unlock(); + + overpopulatedMutex.lock(); + overpopulated.clear(); + overpopulatedMutex.unlock(); + + bornMutex.lock(); + born.clear(); + bornMutex.unlock(); + living.clear(); + Cell itr{ 0, 0 }; while (itr.y < fillArea) { if (std::rand() % livingChance == 0 ) { @@ -143,20 +184,28 @@ void InitializeRandom(size_t livingChance, int64_t fillArea) { void Step() { underpopulatedMutex.lock(); + overpopulatedMutex.lock(); + bornMutex.lock(); + for (Cell const &cell : underpopulated) { living.erase(cell); } - underpopulatedMutex.unlock(); - overpopulatedMutex.lock(); + underpopulated.clear(); + for (Cell const &cell : overpopulated) { living.erase(cell); } - overpopulatedMutex.unlock(); - bornMutex.lock(); + overpopulated.clear(); + for (Cell const &cell : born) { living.insert(cell); } + born.clear(); + + underpopulatedMutex.unlock(); + overpopulatedMutex.unlock(); bornMutex.unlock(); + PopulateChanges(); } @@ -207,6 +256,11 @@ void Draw(SDL_Renderer *renderer, double cellSizePercent) { SDL_RenderRect(renderer, &cellRect); } bornMutex.unlock(); + + if (logGenerationTime) { + SDL_Log("End Generation %lf", double(SDL_GetTicksNS() - generationTime) * 0.0000000001); + logGenerationTime = false; + } } void SetSimulationHovered(bool value) {