Skip to content

Commit

Permalink
temp
Browse files Browse the repository at this point in the history
  • Loading branch information
KRM7 committed Sep 14, 2023
1 parent 74c6516 commit 657fc90
Show file tree
Hide file tree
Showing 23 changed files with 432 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/sanitizers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
fail-fast: false
matrix:
sanitizer: [ address, undefined ]
sanitizer: [ address, undefined, thread ]
include:
- cxx: clang++-15
pkgs: clang-15 llvm-15 libtbb-dev
Expand Down
13 changes: 2 additions & 11 deletions .tsan-supressions
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# Suppress warnings from Intel TBB
# (libstdc++ uses TBB to implement the parallel std algorithms)

# clang
race:^tbb::detail::d1::node::node
race:^tbb::detail::d1::tree_node::tree_node

Expand All @@ -14,10 +10,5 @@ race:tbb::detail::d1::small_object_allocator::delete_object

race:tbb::detail::d1::dynamic_grainsize_mode<*>::check_being_stolen

race:^tbb::detail::d1::start_for<*>::finalize

# This supression is just supposed to be the first one, but the function name isnt always displayed properly in the stack trace
race:^tbb::detail::d1::start_for<*>::offer_work
race:tbb::detail::d1::auto_partitioner const>::offer_work(tbb::detail::d0::split&, tbb::detail::d1::execution_data&)

race:^tbb::detail::r1::isolate_within_arena
race:tbb::detail::d1::start_for<*>::finalize
race:tbb::detail::d1::start_for<*>::offer_work_impl
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ if(GAPP_BUILD_TESTS AND BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/test/unit")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/test/integration")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/test/misc")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/test/tsan")
endif()

if(GAPP_BUILD_BENCHMARKS AND BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
Expand Down
7 changes: 4 additions & 3 deletions src/algorithm/nd_sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "../utility/algorithm.hpp"
#include "../utility/functional.hpp"
#include "../utility/iterators.hpp"
#include "../utility/parallel_for.hpp"
#include "../utility/math.hpp"
#include "../utility/utility.hpp"
#include "../utility/matrix.hpp"
Expand Down Expand Up @@ -90,7 +91,7 @@ namespace gapp::algorithm::dtl
{
const size_t popsize = std::distance(first, last);

thread_local DominanceLists dom_lists;
static DominanceLists dom_lists;

if (dom_lists.size() != popsize)
{
Expand Down Expand Up @@ -188,7 +189,7 @@ namespace gapp::algorithm::dtl
const size_t popsize = std::distance(first, last);
DominanceMatrix dmat(popsize, popsize /*, MAXIMAL */);

std::for_each(GAPP_EXEC_UNSEQ, detail::iota_iterator(0_sz), detail::iota_iterator(first->size()), [&](size_t obj)
detail::parallel_for(detail::iota_iterator(0_sz), detail::iota_iterator(first->size()), [&](size_t obj)
{
FitnessVector fvec(popsize);
std::transform(first, last, fvec.begin(), detail::element_at(obj));
Expand All @@ -212,7 +213,7 @@ namespace gapp::algorithm::dtl
});
});

std::for_each(GAPP_EXEC_UNSEQ, detail::iota_iterator(0_sz), detail::iota_iterator(popsize), [&](size_t row) noexcept
detail::parallel_for(detail::iota_iterator(0_sz), detail::iota_iterator(popsize), [&](size_t row) noexcept
{
dmat(row, row).store(NONMAXIMAL, std::memory_order_relaxed); // diagonal is all nonmax

Expand Down
3 changes: 2 additions & 1 deletion src/algorithm/nsga3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../metrics/pop_stats.hpp"
#include "../utility/algorithm.hpp"
#include "../utility/functional.hpp"
#include "../utility/parallel_for.hpp"
#include "../utility/math.hpp"
#include "../utility/rng.hpp"
#include "../utility/utility.hpp"
Expand Down Expand Up @@ -239,7 +240,7 @@ namespace gapp::algorithm

sol_info_.resize(last - first);

std::for_each(GAPP_EXEC_UNSEQ, pfirst, plast, [&](const FrontInfo& sol)
detail::parallel_for(pfirst, plast, [&](const FrontInfo& sol)
{
const FitnessVector fnorm = normalizeFitnessVec(first[sol.idx], ideal_point_, nadir_point_);

Expand Down
9 changes: 4 additions & 5 deletions src/algorithm/reference_lines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,11 @@ namespace gapp::algorithm::reflines
min_distances.pop_back();

/* Calc the distance of each candidate to the closest ref point. */
std::transform(GAPP_EXEC_UNSEQ, candidate_points.begin(), candidate_points.end(), min_distances.begin(), min_distances.begin(),
[&](const Point& candidate, double current_min) noexcept
for (size_t i = 0; i < candidate_points.size(); i++)
{
const double dist = math::euclideanDistanceSq(candidate, points.back());
return std::min(current_min, dist);
});
double dist = math::euclideanDistanceSq(candidate_points[i], points.back());
min_distances[i] = std::min(min_distances[i], dist);
}
}

return points;
Expand Down
19 changes: 9 additions & 10 deletions src/core/ga_base.impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "../stop_condition/stop_condition_base.hpp"
#include "../utility/algorithm.hpp"
#include "../utility/functional.hpp"
#include "../utility/parallel_for.hpp"
#include "../utility/scope_exit.hpp"
#include "../utility/utility.hpp"
#include <algorithm>
Expand Down Expand Up @@ -327,7 +328,7 @@ namespace gapp

/* Reset state in case solve() has already been called before. */
generation_cntr_ = 0;
num_fitness_evals_ = 0;
num_fitness_evals_->store(0, std::memory_order_relaxed);
solutions_.clear();
population_.clear();

Expand All @@ -339,7 +340,7 @@ namespace gapp
/* Create and evaluate the initial population of the algorithm. */
num_objectives_ = findNumberOfObjectives();
population_ = generatePopulation(population_size_, std::move(initial_population));
std::for_each(GAPP_EXEC_UNSEQ, population_.begin(), population_.end(), [this](Candidate<T>& sol) { evaluate(sol); });
detail::parallel_for(population_.begin(), population_.end(), [this](Candidate<T>& sol) { evaluate(sol); });
fitness_matrix_ = detail::toFitnessMatrix(population_);
if (keep_all_optimal_sols_) solutions_ = detail::findParetoFront(population_);

Expand Down Expand Up @@ -465,11 +466,10 @@ namespace gapp
* is no point doing it again. */
if (!sol.is_evaluated || fitness_function_->dynamic())
{
num_fitness_evals_->fetch_add(1, std::memory_order_release);

sol.fitness = (*fitness_function_)(sol.chromosome);
sol.is_evaluated = true;

std::atomic_ref num_evals{ num_fitness_evals_ };
num_evals.fetch_add(1_sz, std::memory_order_acq_rel);
}

GAPP_ASSERT(hasValidFitness(sol));
Expand Down Expand Up @@ -504,21 +504,20 @@ namespace gapp
std::vector<CandidatePair<T>> child_pairs(num_children / 2);

prepareSelections();
std::generate(GAPP_EXEC_UNSEQ, child_pairs.begin(), child_pairs.end(),
[this]
detail::parallel_for(child_pairs.begin(), child_pairs.end(),
[this](CandidatePair<T>& children)
{
const auto& parent1 = select();
const auto& parent2 = select();

return crossover(parent1, parent2);
children = crossover(parent1, parent2);
});

auto children = detail::flatten(std::move(child_pairs));

/* If the population size is odd, one too many child candidates were generated by the crossovers. */
if (children.size() > population_size_) children.pop_back();

std::for_each(GAPP_EXEC_UNSEQ, children.begin(), children.end(),
detail::parallel_for(children.begin(), children.end(),
[this](Candidate<T>& child)
{
mutate(child);
Expand Down
6 changes: 2 additions & 4 deletions src/core/ga_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "../algorithm/single_objective.hpp"
#include "../stop_condition/stop_condition.hpp"
#include "../utility/utility.hpp"
#include <atomic>
#include <memory>
#include <utility>

Expand All @@ -13,7 +12,7 @@ namespace gapp
GaInfo::GaInfo(GaInfo&&) noexcept = default;
GaInfo& GaInfo::operator=(GaInfo&&) noexcept = default;

GaInfo::~GaInfo() = default;
GaInfo::~GaInfo() noexcept = default;


GaInfo::GaInfo(Positive<size_t> population_size, std::unique_ptr<algorithm::Algorithm> algorithm, std::unique_ptr<stopping::StopCondition> stop_condition) noexcept :
Expand All @@ -26,8 +25,7 @@ namespace gapp

size_t GaInfo::num_fitness_evals() const noexcept
{
std::atomic_ref num_fitness_evals{ num_fitness_evals_ };
return num_fitness_evals.load(std::memory_order_acquire);
return num_fitness_evals_->load(std::memory_order_acquire);
}

void GaInfo::algorithm(std::unique_ptr<algorithm::Algorithm> f)
Expand Down
5 changes: 3 additions & 2 deletions src/core/ga_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "../population/population.hpp"
#include "../utility/bounded_value.hpp"
#include "../utility/atomic.hpp"
#include "../utility/utility.hpp"
#include "../metrics/metric_set.hpp"
#include <functional>
Expand Down Expand Up @@ -341,7 +342,7 @@ namespace gapp
GaInfo& operator=(const GaInfo&) = delete;

/** Destructor. */
virtual ~GaInfo();
virtual ~GaInfo() noexcept;

protected:

Expand All @@ -359,7 +360,7 @@ namespace gapp
Positive<size_t> max_gen_ = 500;
size_t num_objectives_ = 0;
size_t generation_cntr_ = 0;
size_t num_fitness_evals_ = 0;
detail::atomic<size_t> num_fitness_evals_ = 0;

bool keep_all_optimal_sols_ = false;
bool use_default_algorithm_ = false;
Expand Down
8 changes: 5 additions & 3 deletions src/metrics/pop_stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "../population/population.hpp"
#include "../utility/algorithm.hpp"
#include "../utility/iterators.hpp"
#include "../utility/parallel_for.hpp"
#include "../utility/utility.hpp"
#include <vector>
#include <span>
Expand Down Expand Up @@ -154,17 +155,18 @@ namespace gapp::detail
const FitnessMatrix front = uniqueSortedParetoFront(fmat);

std::atomic<double> hypervolume = 0.0;
std::for_each(GAPP_EXEC_UNSEQ, detail::iota_iterator(0_sz), detail::iota_iterator(front.size()), [&](size_t idx)

detail::parallel_for(detail::iota_iterator(0_sz), detail::iota_iterator(front.size()), [&](size_t idx)
{
const auto point = front[idx];
const FitnessMatrix rest = { front.begin() + idx + 1, front.end() };

const double exclusive_hypervolume = exclusiveHypervolume(point, rest, ref_point);

hypervolume.fetch_add(exclusive_hypervolume, std::memory_order_acq_rel);
hypervolume.fetch_add(exclusive_hypervolume, std::memory_order_relaxed);
});

return hypervolume.load(std::memory_order_acquire);
return hypervolume.load(std::memory_order_relaxed);
}

static inline double hypervolume(seq, const FitnessMatrix& fmat, std::span<const double> ref_point)
Expand Down
10 changes: 6 additions & 4 deletions src/population/population.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ namespace gapp::detail
#include "../utility/algorithm.hpp"
#include "../utility/functional.hpp"
#include "../utility/iterators.hpp"
#include "../utility/parallel_for.hpp"
#include "../utility/utility.hpp"
#include "../utility/math.hpp"
#include <algorithm>
Expand Down Expand Up @@ -87,7 +88,6 @@ namespace gapp::detail
GAPP_ASSERT(std::all_of(pop.begin(), pop.end(), [&](const Candidate<T>& sol) { return sol.fitness.size() == pop[0].fitness.size(); }));

auto fitness_matrix = detail::toFitnessMatrix(pop);

auto optimal_indices = detail::findParetoFront(fitness_matrix);

return detail::select(pop, optimal_indices);
Expand All @@ -106,7 +106,7 @@ namespace gapp::detail
std::vector<Dominance> lhs_state(lhs.size());
std::vector<std::atomic<Dominance>> rhs_state(rhs.size());

std::for_each(GAPP_EXEC_UNSEQ, iota_iterator(0_sz), iota_iterator(lhs.size()), [&](size_t i) noexcept
detail::parallel_for(iota_iterator(0_sz), iota_iterator(lhs.size()), [&](size_t i) noexcept
{
for (size_t j = 0; j < rhs.size(); j++)
{
Expand Down Expand Up @@ -152,11 +152,13 @@ namespace gapp::detail

for (size_t i = 0; i < rhs.size(); i++)
{
if (rhs_state[i].load(std::memory_order_relaxed) != DOMINATED) optimal_solutions.push_back(std::move(rhs[i]));
if (rhs_state[i].load(std::memory_order_relaxed) != DOMINATED)
optimal_solutions.push_back(std::move(rhs[i]));
}
for (size_t i = 0; i < lhs.size(); i++)
{
if (lhs_state[i] != DOMINATED) optimal_solutions.push_back(std::move(lhs[i]));
if (lhs_state[i] != DOMINATED)
optimal_solutions.push_back(std::move(lhs[i]));
}

return optimal_solutions;
Expand Down
64 changes: 64 additions & 0 deletions src/utility/atomic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* Copyright (c) 2023 Krisztián Rugási. Subject to the MIT License. */

#ifndef GA_UTILITY_ATOMIC_HPP
#define GA_UTILITY_ATOMIC_HPP

#include <atomic>
#include <memory>
#include <utility>

namespace gapp::detail
{
/*
* This is a simple wrapper class around std::atomic with atomic
* initialization, in order to prevent data races between the
* initialization of the variable and later accesses to it.
*
* The wrapper also adds move operators for convenience.
*/
template<typename T>
class atomic
{
public:
atomic(std::memory_order order = std::memory_order_seq_cst) noexcept
{
data_.store(T{}, order);
}

atomic(T value, std::memory_order order = std::memory_order_seq_cst) noexcept
{
data_.store(std::move(value), order);
}

atomic(atomic<T>&& other) noexcept
{
data_.store(other->load());
}

atomic<T>& operator=(T value) noexcept
{
data_.store(std::move(value));
return *this;
}

atomic<T>& operator=(atomic<T>&& other) noexcept
{
data_.store(other->load());
return *this;
}

~atomic() noexcept = default; // maybe needs release?

std::atomic<T>& operator*() noexcept { return data_; }
std::atomic<T>* operator->() noexcept { return std::addressof(data_); }
const std::atomic<T>& operator*() const noexcept { return data_; }
const std::atomic<T>* operator->() const noexcept { return std::addressof(data_); }

private:
std::atomic<T> data_;
};


} // namespace gapp::detail

#endif // !GA_UTILITY_ATOMIC_HPP
Loading

0 comments on commit 657fc90

Please sign in to comment.