memory_orders on load operations
:Release Notes: removed jthread, either way explicit join additional bench test (separate mutex and unordered map) :Detailed Notes: - :Testing Performed: just tests/bench run - output is correct, no data races detected (-fsanitize=thread) :QA Notes: - :Issues Addressed: -
This commit is contained in:
parent
b958d407f1
commit
4c008aa77c
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"editor.defaultFormatter": "xaver.clang-format",
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
||||||
@ -94,23 +94,35 @@ static void BM_taylor_atomic_upd(benchmark::State& state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updValue(double res, const std::string& key) {
|
void updMapValue(double res, const std::string& key) {
|
||||||
static std::unordered_map<std::string, double> d = {{"key", 10.0},
|
static std::unordered_map<std::string, double> d = {{"key", 10.0},
|
||||||
{"assembly", 11.0},
|
{"assembly", 11.0},
|
||||||
{"draw", 123.3},
|
{"draw", 123.3},
|
||||||
{"d2", 0.0},
|
{"d2", 0.0},
|
||||||
{"d55", 0.23}};
|
{"d55", 0.23}};
|
||||||
|
d[key] = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void BM_taylor_map_upd(benchmark::State& state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
double res = calc_exp_taylor();
|
||||||
|
updMapValue(res, "assembly");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updValue(double res) {
|
||||||
|
static double d;
|
||||||
static std::mutex mtx;
|
static std::mutex mtx;
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mtx);
|
std::lock_guard lock(mtx);
|
||||||
d[key] = res;
|
d = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BM_taylor_mutex_upd(benchmark::State& state) {
|
static void BM_taylor_mutex_upd(benchmark::State& state) {
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
double res = calc_exp_taylor();
|
double res = calc_exp_taylor();
|
||||||
updValue(res, "assembly");
|
updValue(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +131,7 @@ BENCHMARK(BM_taylor_logger);
|
|||||||
BENCHMARK(BM_taylor_glog);
|
BENCHMARK(BM_taylor_glog);
|
||||||
BENCHMARK(BM_taylor_atomic_upd);
|
BENCHMARK(BM_taylor_atomic_upd);
|
||||||
BENCHMARK(BM_taylor_mutex_upd);
|
BENCHMARK(BM_taylor_mutex_upd);
|
||||||
|
BENCHMARK(BM_taylor_map_upd);
|
||||||
|
|
||||||
std::string caesar_encoder(const std::string& input) {
|
std::string caesar_encoder(const std::string& input) {
|
||||||
static constexpr int small = 'a';
|
static constexpr int small = 'a';
|
||||||
|
|||||||
@ -22,10 +22,13 @@ class Logger {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Logger();
|
virtual ~Logger();
|
||||||
|
|
||||||
|
Logger();
|
||||||
explicit Logger(std::ostream& out);
|
explicit Logger(std::ostream& out);
|
||||||
Logger() = delete;
|
|
||||||
Logger(Logger&) = delete;
|
Logger(Logger&) = delete;
|
||||||
Logger(Logger&&) = delete;
|
Logger(Logger&&) = delete;
|
||||||
|
Logger& operator=(Logger&) = delete;
|
||||||
|
Logger& operator=(Logger&&) = delete;
|
||||||
|
|
||||||
/// @return success or not (already configured)
|
/// @return success or not (already configured)
|
||||||
bool configure(const std::vector<std::string>& d);
|
bool configure(const std::vector<std::string>& d);
|
||||||
@ -33,11 +36,11 @@ class Logger {
|
|||||||
template <typename Metric,
|
template <typename Metric,
|
||||||
typename = std::enable_if_t<std::is_arithmetic_v<Metric>>>
|
typename = std::enable_if_t<std::is_arithmetic_v<Metric>>>
|
||||||
void add(const std::string& field, Metric metric) {
|
void add(const std::string& field, Metric metric) {
|
||||||
auto locked = active.load();
|
auto locked = active.load(std::memory_order_acquire);
|
||||||
// auto locked = active;
|
// auto locked = active;
|
||||||
auto it = locked->find(field);
|
auto it = locked->find(field);
|
||||||
if (it == locked->end()) {
|
if (it == locked->end()) {
|
||||||
throw configErrorMsg;
|
throw configErrorMsg; // additional 30ns on bench ?
|
||||||
}
|
}
|
||||||
it->second = metric;
|
it->second = metric;
|
||||||
}
|
}
|
||||||
@ -51,7 +54,8 @@ class Logger {
|
|||||||
std::unique_ptr<Worker> worker;
|
std::unique_ptr<Worker> worker;
|
||||||
std::shared_ptr<map_type> m1, m2;
|
std::shared_ptr<map_type> m1, m2;
|
||||||
std::atomic<std::shared_ptr<map_type>> active; // impl may use mutex!
|
std::atomic<std::shared_ptr<map_type>> active; // impl may use mutex!
|
||||||
// std::shared_ptr<map_type> active;
|
// std::shared_ptr<map_type> active; // data race without atomic on swap
|
||||||
|
// operation
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vptyp
|
} // namespace vptyp
|
||||||
@ -1,4 +1,6 @@
|
|||||||
#include "logger.hh"
|
#include "logger.hh"
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
namespace vptyp {
|
namespace vptyp {
|
||||||
|
|
||||||
@ -18,6 +20,11 @@ bool Logger::configure(const std::vector<std::string>& d) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger::Logger()
|
||||||
|
: m1(std::make_shared<map_type>()), m2(std::make_shared<map_type>()) {
|
||||||
|
worker = std::make_unique<Logger::Worker>(*this, std::cout);
|
||||||
|
}
|
||||||
|
|
||||||
Logger::Logger(std::ostream& out)
|
Logger::Logger(std::ostream& out)
|
||||||
: m1(std::make_shared<map_type>()), m2(std::make_shared<map_type>()) {
|
: m1(std::make_shared<map_type>()), m2(std::make_shared<map_type>()) {
|
||||||
worker = std::make_unique<Logger::Worker>(*this, out);
|
worker = std::make_unique<Logger::Worker>(*this, out);
|
||||||
@ -31,7 +38,7 @@ class Logger::Worker {
|
|||||||
public:
|
public:
|
||||||
explicit Worker(Logger& father, std::ostream& out)
|
explicit Worker(Logger& father, std::ostream& out)
|
||||||
: parent(father), out(out) {
|
: parent(father), out(out) {
|
||||||
thread = std::jthread([this] { routine(); });
|
thread = std::thread([this] { routine(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
~Worker() {
|
~Worker() {
|
||||||
@ -54,14 +61,14 @@ class Logger::Worker {
|
|||||||
std::atomic<State> state;
|
std::atomic<State> state;
|
||||||
Logger& parent;
|
Logger& parent;
|
||||||
std::ostream& out;
|
std::ostream& out;
|
||||||
std::jthread thread;
|
std::thread thread; // jthread not needed, as we anyway must wait for join
|
||||||
};
|
};
|
||||||
|
|
||||||
void Logger::Worker::unroll() {
|
void Logger::Worker::unroll() {
|
||||||
if (!parent.isConfigured())
|
if (!parent.isConfigured())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto tmp = parent.active.load();
|
auto tmp = parent.active.load(std::memory_order_acquire);
|
||||||
// auto tmp = parent.active;
|
// auto tmp = parent.active;
|
||||||
auto toBeActive = tmp == parent.m1 ? parent.m2 : parent.m1;
|
auto toBeActive = tmp == parent.m1 ? parent.m2 : parent.m1;
|
||||||
while (!parent.active.compare_exchange_weak(tmp, toBeActive)) {
|
while (!parent.active.compare_exchange_weak(tmp, toBeActive)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user