feat: fixed incorrect behaviour on simulation and added benchmarking code

This commit is contained in:
Sara Gerretsen 2025-09-22 23:13:19 +02:00
parent 1ce447208b
commit 98ee5fd73d

View file

@ -1,4 +1,5 @@
#include "simulation.h" #include "simulation.h"
#include "SDL3/SDL_timer.h"
#include "input.h" #include "input.h"
#include "thread_pool.h" #include "thread_pool.h"
#include <SDL3/SDL_log.h> #include <SDL3/SDL_log.h>
@ -77,10 +78,15 @@ static size_t CountNeighbors(Cell const &cell) {
static std::mutex underpopulatedMutex, overpopulatedMutex, bornMutex; static std::mutex underpopulatedMutex, overpopulatedMutex, bornMutex;
static void FindOverpopulated() { static void FindOverpopulated(size_t segment, size_t length) {
overpopulatedMutex.lock(); overpopulatedMutex.lock();
overpopulated.clear(); std::set<Cell>::iterator begin{ living.begin() };
std::ranges::copy_if(living, std::back_inserter(overpopulated), std::set<Cell>::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 { [&](Cell const &c) -> bool {
size_t const neighbors{ CountNeighbors(c) }; size_t const neighbors{ CountNeighbors(c) };
return neighbors > 3; return neighbors > 3;
@ -88,10 +94,16 @@ static void FindOverpopulated() {
overpopulatedMutex.unlock(); overpopulatedMutex.unlock();
} }
static void FindUnderpopulated() { static void FindUnderpopulated(size_t segment, size_t length) {
uint64_t ns{ SDL_GetTicksNS() };
underpopulatedMutex.lock(); underpopulatedMutex.lock();
underpopulated.clear(); std::set<Cell>::iterator begin{ living.begin() };
std::ranges::copy_if(living, std::back_inserter(underpopulated), std::set<Cell>::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 { [&](Cell const &c) -> bool {
size_t const neighbors{ CountNeighbors(c) }; size_t const neighbors{ CountNeighbors(c) };
return neighbors < 2; return neighbors < 2;
@ -99,11 +111,17 @@ static void FindUnderpopulated() {
underpopulatedMutex.unlock(); underpopulatedMutex.unlock();
} }
static void FindBorn() { static void FindBorn(size_t segment, size_t length) {
uint64_t ns{ SDL_GetTicksNS() };
bornMutex.lock(); bornMutex.lock();
born.clear(); std::set<Cell>::iterator itr{ living.begin() };
for (Cell const &cell : living) { std::set<Cell>::iterator end{ living.begin() };
std::vector<Cell> neighbors{ NeighborSet(cell) };
std::advance(itr, segment * length);
std::advance(end, segment * length + length);
for (;itr != end; ++itr) {
std::vector<Cell> neighbors{ NeighborSet(*itr) };
std::ranges::copy_if(neighbors, std::back_inserter(born), std::ranges::copy_if(neighbors, std::back_inserter(born),
[&](Cell const &c) -> bool { [&](Cell const &c) -> bool {
size_t const neighbors{ CountNeighbors(c) }; size_t const neighbors{ CountNeighbors(c) };
@ -113,20 +131,43 @@ static void FindBorn() {
bornMutex.unlock(); bornMutex.unlock();
} }
#define MULTITHREADING 0
static uint64_t generationTime{ 0 };
static bool logGenerationTime{ false };
static void PopulateChanges() { static void PopulateChanges() {
#if 1 generationTime = SDL_GetTicksNS();
threading::tasks.ScheduleTask(&FindOverpopulated); logGenerationTime = true;
threading::tasks.ScheduleTask(&FindUnderpopulated); #if MULTITHREADING
threading::tasks.ScheduleTask(&FindBorn); 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 #else
FindOverpopulated(); FindOverpopulated(0, living.size());
FindUnderpopulated(); FindUnderpopulated(0, living.size());
FindBorn(); FindBorn(0, living.size());
#endif #endif
} }
void InitializeRandom(size_t livingChance, int64_t fillArea) { 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(); living.clear();
Cell itr{ 0, 0 }; Cell itr{ 0, 0 };
while (itr.y < fillArea) { while (itr.y < fillArea) {
if (std::rand() % livingChance == 0 ) { if (std::rand() % livingChance == 0 ) {
@ -143,20 +184,28 @@ void InitializeRandom(size_t livingChance, int64_t fillArea) {
void Step() { void Step() {
underpopulatedMutex.lock(); underpopulatedMutex.lock();
overpopulatedMutex.lock();
bornMutex.lock();
for (Cell const &cell : underpopulated) { for (Cell const &cell : underpopulated) {
living.erase(cell); living.erase(cell);
} }
underpopulatedMutex.unlock(); underpopulated.clear();
overpopulatedMutex.lock();
for (Cell const &cell : overpopulated) { for (Cell const &cell : overpopulated) {
living.erase(cell); living.erase(cell);
} }
overpopulatedMutex.unlock(); overpopulated.clear();
bornMutex.lock();
for (Cell const &cell : born) { for (Cell const &cell : born) {
living.insert(cell); living.insert(cell);
} }
born.clear();
underpopulatedMutex.unlock();
overpopulatedMutex.unlock();
bornMutex.unlock(); bornMutex.unlock();
PopulateChanges(); PopulateChanges();
} }
@ -207,6 +256,11 @@ void Draw(SDL_Renderer *renderer, double cellSizePercent) {
SDL_RenderRect(renderer, &cellRect); SDL_RenderRect(renderer, &cellRect);
} }
bornMutex.unlock(); bornMutex.unlock();
if (logGenerationTime) {
SDL_Log("End Generation %lf", double(SDL_GetTicksNS() - generationTime) * 0.0000000001);
logGenerationTime = false;
}
} }
void SetSimulationHovered(bool value) { void SetSimulationHovered(bool value) {