i think the silly little data races are fixed now

thread
Brett 2024-07-12 14:09:45 -04:00
parent 821ffa3aa9
commit c4cff07210
4 changed files with 86 additions and 43 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(blt-gp VERSION 0.0.63) project(blt-gp VERSION 0.0.64)
include(CTest) include(CTest)

View File

@ -48,7 +48,7 @@ namespace blt::gp
std::reference_wrapper<crossover_t> crossover; std::reference_wrapper<crossover_t> crossover;
std::reference_wrapper<population_initializer_t> pop_initializer; std::reference_wrapper<population_initializer_t> 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! // 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; blt::size_t evaluation_size = 4;

View File

@ -283,9 +283,54 @@ namespace blt::gp
{ {
current_pop = config.pop_initializer.get().generate( current_pop = config.pop_initializer.get().generate(
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); {*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) { thread_execution_service = new std::function([this, &fitness_function]() {
fitness_function(current_tree, fitness, index); 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(); evaluate_fitness_internal();
} }
@ -429,6 +474,9 @@ namespace blt::gp
if (thread->joinable()) if (thread->joinable())
thread->join(); thread->join();
} }
auto* cpy = thread_execution_service.load(std::memory_order_acquire);
thread_execution_service = nullptr;
delete cpy;
} }
private: private:
@ -454,7 +502,7 @@ namespace blt::gp
} thread_helper; } thread_helper;
// for convenience, shouldn't decrease performance too much // for convenience, shouldn't decrease performance too much
std::function<void(tree_t&, fitness_t&, blt::size_t)> evaluate_fitness_func; std::atomic<std::function<void()>*> thread_execution_service = nullptr;
inline selector_args get_selector_args() inline selector_args get_selector_args()
{ {
@ -475,40 +523,32 @@ namespace blt::gp
void evaluate_fitness_internal() void evaluate_fitness_internal()
{ {
current_stats.clear(); current_stats.clear();
if (config.threads == 1)
{ {
std::scoped_lock lock(thread_helper.evaluation_control); (*thread_execution_service)();
thread_helper.evaluation_left = current_pop.get_individuals().size(); } else
thread_helper.threads_left = static_cast<blt::i64>(config.threads) + 1; {
{
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<double>(config.population_size); current_stats.average_fitness = current_stats.overall_fitness / static_cast<double>(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 = {}; /*current_stats = {};
for (const auto& ind : blt::enumerate(current_pop.get_individuals())) for (const auto& ind : blt::enumerate(current_pop.get_individuals()))

View File

@ -53,13 +53,16 @@ namespace blt::gp
void gp_program::create_threads() void gp_program::create_threads()
{ {
if (config.threads == 0) if (config.threads == 0)
config.set_thread_count(std::thread::hardware_concurrency() - 1); config.set_thread_count(std::thread::hardware_concurrency());
for (blt::size_t i = 0; i < config.threads; i++) // main thread is thread0
for (blt::size_t i = 1; i < config.threads; i++)
{ {
thread_helper.threads.emplace_back(new std::thread([this]() { thread_helper.threads.emplace_back(new std::thread([this]() {
while (!should_thread_terminate()) 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) if (thread_helper.evaluation_left > 0)
{ {
//std::cout << "Thread beginning" << std::endl; std::cout << "Thread beginning" << std::endl;
while (thread_helper.evaluation_left > 0) while (thread_helper.evaluation_left > 0)
{ {
blt::size_t begin = 0; blt::size_t begin = 0;
@ -81,12 +84,12 @@ namespace blt::gp
begin = thread_helper.evaluation_left - size; begin = thread_helper.evaluation_left - size;
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++) for (blt::size_t i = begin; i < end; i++)
{ {
auto& ind = current_pop.get_individuals()[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(); auto old_best = current_stats.best_fitness.load();
while (ind.fitness.adjusted_fitness > old_best && while (ind.fitness.adjusted_fitness > old_best &&
@ -104,7 +107,7 @@ namespace blt::gp
} }
} }
thread_helper.threads_left--; thread_helper.threads_left--;
//std::cout << "thread finished!" << std::endl; std::cout << "thread finished!" << std::endl;
} }
} }
} }