feat: fixed incorrect behaviour on simulation and added benchmarking code
This commit is contained in:
parent
1ce447208b
commit
98ee5fd73d
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue