1 Commits

10 changed files with 91 additions and 146 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
*.idb
*.pdb
**obj** **obj**
**bin** **bin**
.cache** .cache**

View File

@@ -1 +1 @@
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" && bash "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"

10
build.bat Normal file
View File

@@ -0,0 +1,10 @@
@ECHO off
SET flags=-Od -ZI -MTd
SET config=Debug
IF "%1" == "release" (
SET flags=-O2 -MT
SET config=Release
)
SET srcs=src\*
mkdir bin obj
cl %srcs% -I inc %flags% -std:c++20 -MP -Fo:obj\\ -Fe:bin\\

View File

@@ -1,13 +0,0 @@
(
cd bin
rm main.*
srcs=../src/*
if [ $# -eq 1 ] && [ "$1" == "release" ]
then
flags="-O2"
else
flags="-Od -ZI"
fi
echo $flags
cl $srcs -I ../inc/ $flags -std:c++20 -Fe
)

View File

@@ -1,5 +1,11 @@
// raddbg 0.9.21 project file // raddbg 0.9.21 project file
recent_file: path: "C:/Program Files (x86)/Windows Kits/10/include/10.0.26100.0/ucrt/stdio.h"
recent_file: path: "d:/os/obj/amd64fre/minkernel/crts/ucrt/src/appcrt/stdio/xmt/objfre/amd64/minkernel/crts/ucrt/src/appcrt/stdio/output.cpp"
recent_file: path: "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.44.35207/include/xutility"
recent_file: path: "C:/Users/sethh/Documents/repos/Petri/inc/genetic.h"
recent_file: path: "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.44.35207/include/algorithm"
recent_file: path: "C:/Users/sethh/Documents/repos/Petri/inc/sync.h"
recent_file: path: "inc/genetic.h" recent_file: path: "inc/genetic.h"
recent_file: path: "inc/sync.h" recent_file: path: "inc/sync.h"
recent_file: path: "d:/os/obj/amd64fre/minkernel/crts/ucrt/src/appcrt/startup/mt/objfre/amd64/minkernel/crts/ucrt/src/appcrt/startup/abort.cpp" recent_file: path: "d:/os/obj/amd64fre/minkernel/crts/ucrt/src/appcrt/startup/mt/objfre/amd64/minkernel/crts/ucrt/src/appcrt/startup/abort.cpp"
@@ -21,5 +27,5 @@ target:
breakpoint: breakpoint:
{ {
source_location: "inc/genetic.h:292:1" source_location: "inc/genetic.h:292:1"
hit_count: 1 hit_count: 0
} }

22
export.bat Normal file
View File

@@ -0,0 +1,22 @@
@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO [ > compile_commands.json
FOR /r "src\" %%F IN (*.cpp) DO (
SET "file=%%F"
SET "file=!file:\=/!"
SET "directory=%~dp0"
SET "directory=!directory:\=/!"
ECHO { >> compile_commands.json
ECHO "directory": "!directory!", >> compile_commands.json
ECHO "command": "cl !file! -I inc %flags% -std:c++20 -MP -Fo:obj\\ ", >> compile_commands.json
ECHO "file": "!file!" >> compile_commands.json
ECHO }, >> compile_commands.json
)
ECHO ] >> compile_commands.json

View File

@@ -1,5 +0,0 @@
srcs=src/*
echo [ > compile_commands.json
find src -iname "*.cpp" -exec sh -c 'echo { \"directory\": \"$(cygpath -m $(pwd))\", \"command\": \"cl "$(cygpath -m {})" -I inc -Od -std:c++20 -Fo\", \"file\": \"$(cygpath -m {})\" }, >> compile_commands.json' \;
echo ] >> compile_commands.json

View File

@@ -2,6 +2,8 @@
#include <algorithm> #include <algorithm>
#include <cfloat> #include <cfloat>
#include <cstdarg>
#include <cstdio>
#include <cstdlib> #include <cstdlib>
#include "util.h" #include "util.h"
@@ -9,7 +11,6 @@
#include "rand.h" #include "rand.h"
using namespace sync; using namespace sync;
using namespace std;
namespace genetic { namespace genetic {
@@ -17,6 +18,29 @@ template <class T> struct Stats;
template <class T> struct Strategy; template <class T> struct Strategy;
struct CellTracker; struct CellTracker;
const char *global_stat_format_str = "GLOBAL, Progress %.1f%%, Top: %.5e, Overhead Per: %.4f%%, Gen: %.4f, Overhead: %.4f, Cross: %.4f (s), Mutate: %.4f (s), Fitness: %.4f (s), Sorting: %.4f (s)\n";
const char *thread_stat_format_str = "%d, Progress %d/%d, Top: %.5e, Overhead Per: %.4f%%, Gen: %.4f, Overhead: %.4f, Cross: %.4f (s), Mutate: %.4f (s), Fitness: %.4f (s), Sorting: %.4f (s)\n";
static int stat_str_len = 2*max(strlen(thread_stat_format_str), strlen(global_stat_format_str));
static char *stat_str = (char*)malloc(stat_str_len);
static char *filename = (char*)malloc(64);
static int n_threads = 0;
void log(const char *format_str, ...) {
va_list list;
va_start(list, format_str);
vsprintf_s(stat_str, 2*max(strlen(thread_stat_format_str), strlen(global_stat_format_str)), format_str, list);
printf("%s", stat_str);
FILE *f;
sprintf(filename, "logs/logs-%d.txt", n_threads);
fopen_s(&f, filename, "a");
fwrite(stat_str, sizeof(char), strlen(stat_str), f);
fclose(f);
}
template <class T> T run(Strategy<T>); template <class T> T run(Strategy<T>);
template <class T> struct Strategy { template <class T> struct Strategy {
@@ -121,8 +145,6 @@ template <class T> DWORD worker(LPVOID args) {
bool gt = strat.higher_fitness_is_better; // Writing strat.higher... is annoying bool gt = strat.higher_fitness_is_better; // Writing strat.higher... is annoying
// printf("Core: %d\n", get_affinity());
TimeSpan start, diff, gen_start; TimeSpan start, diff, gen_start;
while(stats.gen < strat.num_generations) { while(stats.gen < strat.num_generations) {
gen_start = now(); gen_start = now();
@@ -163,11 +185,7 @@ template <class T> DWORD worker(LPVOID args) {
assert(cell != NULL); assert(cell != NULL);
children[i-child_begin] = cell; children[i-child_begin] = cell;
} }
CrossoverJob<T> cj = {parents, children}; strat.crossover(parents, children);
TaggedJob<T> job;
job.data.c=cj;
job.type=JobType::CROSSOVER;
q.jobs[q.write_i++] = job;
parent_end += strat.crossover_parent_stride; parent_end += strat.crossover_parent_stride;
child_begin -= nchild; child_begin -= nchild;
} }
@@ -192,35 +210,26 @@ template <class T> DWORD worker(LPVOID args) {
start = now(); start = now();
if (strat.test_all) { if (strat.test_all) {
for (int i = 0; i < trackers.len; i++) { for (int i = 0; i < trackers.len; i++) {
FitnessJob<T> fj = {&cells[trackers[i].cellid], &trackers[i]}; trackers[i].score = strat.fitness(cells[trackers[i].cellid]);
TaggedJob<T> job;
job.data.f=fj;
job.type=JobType::FITNESS;
if (i == trackers.len-1) lock(q.m);
q.jobs[q.write_i++] = job;
if (i == trackers.len-1) { q.done_writing = true; unlock(q.m); }
} }
} else { } else {
lock(q.m);
for (int i = 0; i < trackers.len; i++) { for (int i = 0; i < trackers.len; i++) {
if (abs(norm_rand(strat.rand_seed)) < strat.test_chance) { if (abs(norm_rand(strat.rand_seed)) < strat.test_chance) {
FitnessJob<T> fj = {&cells[trackers[i].cellid], &trackers[i]}; trackers[i].score = strat.fitness(cells[trackers[i].cellid]);
TaggedJob<T> job;
job.data.f=fj;
job.type=JobType::FITNESS;
q.jobs[q.write_i++] = job;
} }
} }
q.done_writing = true;
unlock(q.m);
} }
lock(stats.m); lock(stats.m);
append(stats.fitness_time, now() - start); append(stats.fitness_time, now() - start);
unlock(stats.m); unlock(stats.m);
auto comp = [strat](CellTracker &a, CellTracker &b){
return strat.higher_fitness_is_better ? (a.score > b.score) : (a.score < b.score);
};
// 4. sort // 4. sort
start = now(); start = now();
std::sort(&trackers[0], &trackers[trackers.len-1], [strat](CellTracker &a, CellTracker &b){ return better(strat.higher_fitness_is_better, a.score, b.score) == a.score; }); std::sort(&trackers[0], &trackers[trackers.len-1], comp);
lock(stats.m); lock(stats.m);
append(stats.sorting_time, now() - start); append(stats.sorting_time, now() - start);
@@ -274,12 +283,13 @@ template <class T> T run(Strategy<T> strat) {
threads[i] = make_thread(worker<T>, &args[i], i+1); threads[i] = make_thread(worker<T>, &args[i], i+1);
} }
// We are the stats thread // We are the stats thread
bool complete = false; bool complete = false;
while (!complete) { while (!complete) {
sleep(from_s(strat.stats_print_period_s)); sleep(from_s(strat.stats_print_period_s));
printf("**********************\n"); log("**********************\n");
float g_avg_gen_time = 0; float g_avg_gen_time = 0;
float g_avg_crossover_time = 0; float g_avg_crossover_time = 0;
float g_avg_mutate_time = 0; float g_avg_mutate_time = 0;
@@ -291,6 +301,7 @@ template <class T> T run(Strategy<T> strat) {
complete = true; complete = true;
for (int i = 0; i < stats.len; i++) { for (int i = 0; i < stats.len; i++) {
lock(stats[i].m); lock(stats[i].m);
complete &= stats[i].done; complete &= stats[i].done;
@@ -319,7 +330,8 @@ template <class T> T run(Strategy<T> strat) {
g_avg_overhead_time += overhead; g_avg_overhead_time += overhead;
printf("%d, Progress %d/%d, Top: %.5e, Overhead Per: %.4f%%, Gen: %.4f, Overhead: %.4f, Cross: %.4f (s), Mutate: %.4f (s), Fitness: %.4f (s), Sorting: %.4f (s)\n", i, stats[i].gen, strat.num_generations, best_score, overhead_per, gen_time, overhead, crossover_time, mutate_time, fitness_time, sorting_time); log(thread_stat_format_str, i, stats[i].gen, strat.num_generations, best_score, overhead_per, gen_time, overhead, crossover_time, mutate_time, fitness_time, sorting_time);
unlock(stats[i].m); unlock(stats[i].m);
} }
@@ -334,8 +346,8 @@ template <class T> T run(Strategy<T> strat) {
float g_avg_overhead_per = g_avg_overhead_time / g_avg_gen_time * 100; float g_avg_overhead_per = g_avg_overhead_time / g_avg_gen_time * 100;
printf("GLOBAL, Progress %.1f%%, Top: %.5e, Overhead Per: %.4f%%, Gen: %.4f, Overhead: %.4f, Cross: %.4f (s), Mutate: %.4f (s), Fitness: %.4f (s), Sorting: %.4f (s)\n", g_progress_per, g_best_fitness, g_avg_overhead_per, g_avg_gen_time, g_avg_overhead_time, g_avg_crossover_time, g_avg_mutate_time, g_avg_fitness_time, g_avg_sorting_time); log(global_stat_format_str, g_progress_per, g_best_fitness, g_avg_overhead_per, g_avg_gen_time, g_avg_overhead_time, g_avg_crossover_time, g_avg_mutate_time, g_avg_fitness_time, g_avg_sorting_time);
if (complete) break; if (complete) break;
} }
@@ -357,95 +369,4 @@ template <class T> T run(Strategy<T> strat) {
return best_cell; return best_cell;
} }
template<class T> WorkQueue<T> make_work_queue(int len, int batch_size) {
return {
.jobs=make_array<TaggedJob<T>>(len),
.read_i=0,
.write_i=0,
.batch_size=batch_size,
.done_writing=false,
.work_complete=false,
.m=make_mutex(),
.done=make_condition_var(),
.jobs_ready=make_condition_var()
};
}
template<class T> bool tryget_job_batch(WorkQueue<T> &q, Array<TaggedJob<T>>* out_batch, bool* out_batch_is_end) {
lock(q.m);
if (q.stop) {
unlock(q.m);
return false;
}
// Keep waiting till jobs are available
while (q.read_i >= q.write_i) {
wait(q.jobs_ready, q.m, infinite_ts);
if (q.stop) {
unlock(q.m);
return false;
}
}
// Yay! Let's grab some jobs to do
// If the batch we're about to grab moves read_i to write_i and the producer
// is done writing, we should let our callee know it's handling this gen's last
// batch know that way it sets work_complete and signals done.
*out_batch_is_end = q.done_writing && q.read_i + q.batch_size >= q.write_i;
out_batch->data = &q.jobs[q.read_i];
out_batch->len = min(q.batch_size, q.write_i - q.read_i);
q.read_i += q.batch_size;
unlock(q.m);
return true;
}
template<class T>
void work_batch(Array<TaggedJob<T>> batch, Strategy<T> &s) {
for (int i = 0; i < batch.len; i++) {
switch (batch[i].type) {
case JobType::MUTATE: {
MutateJob<T> mj = batch[i].data.m;
s.mutate(*mj.cell);
} break;
case JobType::CROSSOVER: {
CrossoverJob<T> cj = batch[i].data.c;
s.crossover(cj.parents, cj.children);
} break;
case JobType::FITNESS: {
FitnessJob<T> fj = batch[i].data.f;
fj.track->score = s.fitness(*fj.cell);
} break;
default: {
assert(false);
}
}
}
}
template<class T>
DWORD worker(LPVOID args) {
WorkerThreadArgs<T>* wa = static_cast<WorkerThreadArgs<T>*>(args);
WorkQueue<T> &q = wa->q;
Strategy<T> &s = wa->s;
// These are written by tryget_job_batch
bool batch_is_end;
Array<TaggedJob<T>> batch;
while (tryget_job_batch(q, &batch, &batch_is_end)) {
work_batch(batch, s);
if (batch_is_end) {
lock(q.m);
q.work_complete = true;
wake_one(q.done);
unlock(q.m);
}
}
return NULL;
}
} // namespace genetic } // namespace genetic

View File

@@ -19,7 +19,7 @@ typedef LARGE_INTEGER TimeSpan;
typedef DWORD (WINAPI *ThreadFunc)(_In_ LPVOID lpParameter); typedef DWORD (WINAPI *ThreadFunc)(_In_ LPVOID lpParameter);
typedef LPVOID ThreadArg; typedef LPVOID ThreadArg;
const TimeSpan infinite_ts = { .QuadPart=LLONG_MAX }; const TimeSpan infinite_ts = { .QuadPart = LLONG_MAX };
int get_num_cores() { int get_num_cores() {
SYSTEM_INFO sysinfo; SYSTEM_INFO sysinfo;

View File

@@ -75,22 +75,24 @@ int main(int argc, char **argv) {
.crossover=crossover, .crossover=crossover,
.fitness=fitness .fitness=fitness
}; };
n_threads = atoi(argv[1]);
log("Running w/ %d threads\n", atoi(argv[1]));
TimeSpan start = now(); TimeSpan start = now();
auto best_cell = run(strat); auto best_cell = run(strat);
TimeSpan runtime = now() - start; TimeSpan runtime = now() - start;
float sum = 0; float sum = 0;
float product = 1; float product = 1;
printf("Winning cell: "); log("Winning cell: ");
for (int i = 0; i < best_cell.len; i++) { for (int i = 0; i < best_cell.len; i++) {
float val = best_cell[i]; float val = best_cell[i];
sum += val; sum += val;
product *= val; product *= val;
printf("%f ", val); log("%f ", val);
} }
printf("\n"); log("\n");
printf("Final Sum: %f\n", sum); log("Final Sum: %f\n", sum);
printf("Final Product: %f\n", product); log("Final Product: %f\n", product);
printf("Execution Time %d (min) %f (s)\n", static_cast<int>(sync::to_min(runtime)), fmod(to_s(runtime), 60) ); log("Execution Time %d (min) %f (s)\n", static_cast<int>(sync::to_min(runtime)), fmod(to_s(runtime), 60) );
} }