From c4cff07210bb647d09d29a57bd9355152a8ab921 Mon Sep 17 00:00:00 2001 From: Brett Date: Fri, 12 Jul 2024 14:09:45 -0400 Subject: [PATCH] i think the silly little data races are fixed now --- CMakeLists.txt | 2 +- include/blt/gp/config.h | 2 +- include/blt/gp/program.h | 108 +++++++++++++++++++++++++++------------ src/program.cpp | 17 +++--- 4 files changed, 86 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cce2ef..1e1075a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.0.63) +project(blt-gp VERSION 0.0.64) include(CTest) diff --git a/include/blt/gp/config.h b/include/blt/gp/config.h index b65cc6d..22e0ddd 100644 --- a/include/blt/gp/config.h +++ b/include/blt/gp/config.h @@ -48,7 +48,7 @@ namespace blt::gp std::reference_wrapper crossover; std::reference_wrapper pop_initializer; - blt::size_t threads = std::thread::hardware_concurrency() - 1; + blt::size_t threads = std::thread::hardware_concurrency(); // number of elements each thread should pull per execution. this is for granularity performance and can be optimized for better results! blt::size_t evaluation_size = 4; diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index 3b0cdb9..c5c94d4 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -283,9 +283,54 @@ namespace blt::gp { current_pop = config.pop_initializer.get().generate( {*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); - evaluate_fitness_func = [&fitness_function](tree_t& current_tree, fitness_t& fitness, blt::size_t index) { - fitness_function(current_tree, fitness, index); - }; + thread_execution_service = new std::function([this, &fitness_function]() { + if (thread_helper.evaluation_left > 0) + { + std::cout << "Thread Incrementing " << thread_helper.threads_left << std::endl; + auto old_value_start = thread_helper.threads_left.load(std::memory_order::memory_order_acquire); + while (!thread_helper.threads_left.compare_exchange_weak(old_value_start, old_value_start + 1, std::memory_order_release, + std::memory_order_relaxed)); + std::cout << "Thread beginning " << thread_helper.threads_left << std::endl; + while (thread_helper.evaluation_left > 0) + { + blt::size_t begin = 0; + blt::size_t end = 0; + { + std::scoped_lock lock(thread_helper.evaluation_control); + end = thread_helper.evaluation_left; + auto size = std::min(thread_helper.evaluation_left.load(), config.evaluation_size); + begin = thread_helper.evaluation_left - size; + thread_helper.evaluation_left -= size; + } + //std::cout << "Processing " << begin << " to " << end << " with " << thread_helper.evaluation_left << " left" << std::endl; + for (blt::size_t i = begin; i < end; i++) + { + auto& ind = current_pop.get_individuals()[i]; + + fitness_function(ind.tree, ind.fitness, i); + + auto old_best = current_stats.best_fitness.load(); + while (ind.fitness.adjusted_fitness > old_best && + !current_stats.best_fitness.compare_exchange_weak(old_best, ind.fitness.adjusted_fitness, + std::memory_order_release, std::memory_order_relaxed)); + + auto old_worst = current_stats.worst_fitness.load(); + while (ind.fitness.adjusted_fitness < old_worst && + !current_stats.worst_fitness.compare_exchange_weak(old_worst, ind.fitness.adjusted_fitness, + std::memory_order_release, std::memory_order_relaxed)); + + auto old_overall = current_stats.overall_fitness.load(); + while (!current_stats.overall_fitness.compare_exchange_weak(old_overall, ind.fitness.adjusted_fitness + old_overall, + std::memory_order_release, std::memory_order_relaxed)); + } + } + std::cout << "Thread Decrementing " << thread_helper.threads_left << std::endl; + auto old_value = thread_helper.threads_left.load(std::memory_order::memory_order_acquire); + while (!thread_helper.threads_left.compare_exchange_weak(old_value, old_value - 1, std::memory_order_release, + std::memory_order_relaxed)); + std::cout << "Thread Ending " << thread_helper.threads_left << std::endl; + } + }); evaluate_fitness_internal(); } @@ -429,6 +474,9 @@ namespace blt::gp if (thread->joinable()) thread->join(); } + auto* cpy = thread_execution_service.load(std::memory_order_acquire); + thread_execution_service = nullptr; + delete cpy; } private: @@ -454,7 +502,7 @@ namespace blt::gp } thread_helper; // for convenience, shouldn't decrease performance too much - std::function evaluate_fitness_func; + std::atomic*> thread_execution_service = nullptr; inline selector_args get_selector_args() { @@ -475,40 +523,32 @@ namespace blt::gp void evaluate_fitness_internal() { current_stats.clear(); + if (config.threads == 1) { - std::scoped_lock lock(thread_helper.evaluation_control); - thread_helper.evaluation_left = current_pop.get_individuals().size(); - thread_helper.threads_left = static_cast(config.threads) + 1; + (*thread_execution_service)(); + } else + { + { + std::scoped_lock lock(thread_helper.evaluation_control); + thread_helper.evaluation_left = current_pop.get_individuals().size(); + } + + std::cout << "Func" << std::endl; + while (thread_execution_service == nullptr) + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::cout << "Wait" << std::endl; + (*thread_execution_service)(); + std::cout << "FINSIHED WAITING!!!!!!!! " << thread_helper.threads_left << std::endl; + while (thread_helper.threads_left > 0) + { + //std::cout << thread_helper.threads_left << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + std::cout << "Finished" << std::endl; } - //std::cout << "Wait" << std::endl; - execute_thread(); - while (thread_helper.threads_left > 0) - std::this_thread::yield(); - //std::cout << "Finished" << std::endl; - -// for (auto& ind : current_pop.get_individuals()) -// { -// if (ind.fitness.adjusted_fitness > current_stats.best_fitness) -// { -// current_stats.best_fitness = ind.fitness.adjusted_fitness; -// } -// -// if (ind.fitness.adjusted_fitness < current_stats.worst_fitness) -// { -// current_stats.worst_fitness = ind.fitness.adjusted_fitness; -// } -// -// current_stats.overall_fitness = current_stats.overall_fitness + ind.fitness.adjusted_fitness; -// } - current_stats.average_fitness = current_stats.overall_fitness / static_cast(config.population_size); -// -// BLT_INFO("Stats:"); -// BLT_INFO("Average fitness: %lf", current_stats.average_fitness.load()); -// BLT_INFO("Best fitness: %lf", current_stats.best_fitness.load()); -// BLT_INFO("Worst fitness: %lf", current_stats.worst_fitness.load()); -// BLT_INFO("Overall fitness: %lf", current_stats.overall_fitness.load()); + /*current_stats = {}; for (const auto& ind : blt::enumerate(current_pop.get_individuals())) diff --git a/src/program.cpp b/src/program.cpp index b1cf001..3384569 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -53,13 +53,16 @@ namespace blt::gp void gp_program::create_threads() { if (config.threads == 0) - config.set_thread_count(std::thread::hardware_concurrency() - 1); - for (blt::size_t i = 0; i < config.threads; i++) + config.set_thread_count(std::thread::hardware_concurrency()); + // main thread is thread0 + for (blt::size_t i = 1; i < config.threads; i++) { thread_helper.threads.emplace_back(new std::thread([this]() { while (!should_thread_terminate()) { - execute_thread(); + if (thread_execution_service != nullptr) + (*thread_execution_service)(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } })); } @@ -69,7 +72,7 @@ namespace blt::gp { if (thread_helper.evaluation_left > 0) { - //std::cout << "Thread beginning" << std::endl; + std::cout << "Thread beginning" << std::endl; while (thread_helper.evaluation_left > 0) { blt::size_t begin = 0; @@ -81,12 +84,12 @@ namespace blt::gp begin = thread_helper.evaluation_left - size; thread_helper.evaluation_left -= size; } - //std::cout << "Processing " << begin << " to " << end << " with " << thread_helper.evaluation_left << " left" << std::endl; + std::cout << "Processing " << begin << " to " << end << " with " << thread_helper.evaluation_left << " left" << std::endl; for (blt::size_t i = begin; i < end; i++) { auto& ind = current_pop.get_individuals()[i]; - evaluate_fitness_func(ind.tree, ind.fitness, i); + //evaluate_fitness_func(ind.tree, ind.fitness, i); auto old_best = current_stats.best_fitness.load(); while (ind.fitness.adjusted_fitness > old_best && @@ -104,7 +107,7 @@ namespace blt::gp } } thread_helper.threads_left--; - //std::cout << "thread finished!" << std::endl; + std::cout << "thread finished!" << std::endl; } } } \ No newline at end of file