Skip to content

Commit

Permalink
temp2
Browse files Browse the repository at this point in the history
  • Loading branch information
KRM7 committed Sep 9, 2023
1 parent 5ef1778 commit 3f093af
Show file tree
Hide file tree
Showing 14 changed files with 169 additions and 21 deletions.
5 changes: 4 additions & 1 deletion .tsan-supressions
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ race:^tbb::detail::d1::auto_partition_type::is_divisible
race:tbb::detail::d1::small_object_allocator::new_object
race:tbb::detail::d1::small_object_allocator::delete_object

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

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: 7 additions & 0 deletions src/algorithm/nd_sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ namespace gapp::algorithm::dtl
const size_t popsize = std::distance(first, last);
DominanceMatrix dmat(popsize, popsize /*, MAXIMAL */);

GAPP_BARRIER();
std::for_each(GAPP_EXEC, detail::iota_iterator(0_sz), detail::iota_iterator(first->size()), [&](size_t obj)
{
GAPP_BARRIER();
FitnessVector fvec(popsize);
std::transform(first, last, fvec.begin(), detail::element_at(obj));

Expand All @@ -210,10 +212,13 @@ namespace gapp::algorithm::dtl
}
});
});
GAPP_BARRIER();
});
GAPP_BARRIER();

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

for (size_t col = row + 1; col < popsize; col++)
Expand All @@ -224,7 +229,9 @@ namespace gapp::algorithm::dtl
dmat(col, row).store(NONMAXIMAL, std::memory_order_relaxed);
}
}
GAPP_BARRIER();
});
GAPP_BARRIER();

return dmat;
}
Expand Down
4 changes: 4 additions & 0 deletions src/algorithm/nsga3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,10 @@ namespace gapp::algorithm

sol_info_.resize(last - first);

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

auto idistance = [&](const auto& line) { return std::inner_product(fnorm.begin(), fnorm.end(), line.begin(), 0.0); };
Expand All @@ -249,7 +251,9 @@ namespace gapp::algorithm

sol_info_[sol.idx].ref_idx = std::distance(ref_lines_.begin(), closest);
sol_info_[sol.idx].ref_dist = math::perpendicularDistanceSq(*closest, fnorm);
GAPP_BARRIER();
});
GAPP_BARRIER();
}

inline bool NSGA3::Impl::nichedCompare(size_t lhs, size_t rhs) const noexcept
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, 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
26 changes: 17 additions & 9 deletions src/core/ga_base.impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,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_release);
solutions_.clear();
population_.clear();

Expand All @@ -339,7 +339,9 @@ 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, population_.begin(), population_.end(), [this](Candidate<T>& sol) { evaluate(sol); });
GAPP_BARRIER();
std::for_each(GAPP_EXEC, population_.begin(), population_.end(), [this](Candidate<T>& sol) { GAPP_BARRIER(); evaluate(sol); GAPP_BARRIER(); });
GAPP_BARRIER();
fitness_matrix_ = detail::toFitnessMatrix(population_);
if (keep_all_optimal_sols_) solutions_ = detail::findParetoFront(population_);

Expand Down Expand Up @@ -465,11 +467,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_acq_rel);

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,27 +505,34 @@ namespace gapp
std::vector<CandidatePair<T>> child_pairs(num_children / 2);

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

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

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();

GAPP_BARRIER();
std::for_each(GAPP_EXEC, children.begin(), children.end(),
[this](Candidate<T>& child)
{
GAPP_BARRIER();
mutate(child);
repair(child);
evaluate(child);
GAPP_BARRIER();
});
GAPP_BARRIER();

updatePopulation(std::move(children));
if (keep_all_optimal_sols_) updateOptimalSolutions(solutions_, population_);
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
4 changes: 4 additions & 0 deletions src/metrics/pop_stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,19 @@ namespace gapp::detail
const FitnessMatrix front = uniqueSortedParetoFront(fmat);

std::atomic<double> hypervolume = 0.0;
GAPP_BARRIER();
std::for_each(GAPP_EXEC, detail::iota_iterator(0_sz), detail::iota_iterator(front.size()), [&](size_t idx)
{
GAPP_BARRIER();
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);
GAPP_BARRIER();
});
GAPP_BARRIER();

return hypervolume.load(std::memory_order_acquire);
}
Expand Down
4 changes: 4 additions & 0 deletions src/population/population.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ namespace gapp::detail
std::vector<Dominance> lhs_state(lhs.size());
std::vector<std::atomic<Dominance>> rhs_state(rhs.size());

GAPP_BARRIER();
std::for_each(GAPP_EXEC, iota_iterator(0_sz), iota_iterator(lhs.size()), [&](size_t i) noexcept
{
GAPP_BARRIER();
for (size_t j = 0; j < rhs.size(); j++)
{
const Dominance rhs_state_j = rhs_state[j].load(std::memory_order_acquire);
Expand Down Expand Up @@ -145,7 +147,9 @@ namespace gapp::detail
}
// comp == 0 --> both are OPTIMAL or DOMINATED, can't know
}
GAPP_BARRIER();
});
GAPP_BARRIER();

Candidates<T> optimal_solutions;
optimal_solutions.reserve(lhs.size() + rhs.size());
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
5 changes: 5 additions & 0 deletions src/utility/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@
#endif


#include <atomic>
inline std::atomic_bool global_barrier;
#define GAPP_BARRIER() std::ignore = global_barrier.exchange(true, std::memory_order_seq_cst)


namespace gapp
{
constexpr std::size_t operator ""_sz(unsigned long long arg) noexcept
Expand Down
15 changes: 15 additions & 0 deletions test/tsan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
find_package(Catch2 3 REQUIRED)

if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4388")
endif()

file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB_RECURSE TEST_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")

add_executable(tsan_tests ${TEST_SOURCES} ${TEST_HEADERS})

target_link_libraries(tsan_tests PRIVATE Catch2::Catch2WithMain gapp)

include(Catch)
catch_discover_tests(tsan_tests)
35 changes: 35 additions & 0 deletions test/tsan/tsan.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <catch2/catch_test_macros.hpp>
#include <algorithm>
#include <execution>

std::vector numbers = { 0, 1, 2, 3 };
std::mutex mtx;

TEST_CASE("empty", "[tsan]")
{
std::for_each(std::execution::par, numbers.begin(), numbers.end(), [](const auto&) {});
}

TEST_CASE("simple", "[tsan]")
{
{ std::scoped_lock _{ mtx }; }
std::for_each(std::execution::par, numbers.begin(), numbers.end(), [](auto& n) {
std::scoped_lock _{ mtx }; ++n;
});
}

TEST_CASE("race1", "[tsan]")
{
std::vector numbers2{ 0, 1, 2, 3 };
std::for_each(std::execution::par, numbers2.begin(), numbers2.end(), [](auto& n) {
++n;
});
}

TEST_CASE("race2", "[tsan]")
{
std::vector numbers2{ 0, 1, 2, 3 };
std::for_each(std::execution::par, numbers2.begin(), numbers2.end(), [](auto& n) {
numbers[0] += n;
});
}

0 comments on commit 3f093af

Please sign in to comment.