summaryrefslogtreecommitdiffstats
path: root/vespalib/src
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@yahooinc.com>2023-06-20 14:23:30 +0000
committerHåvard Pettersen <havardpe@yahooinc.com>2023-06-20 14:23:30 +0000
commitcea896a6fad5be3d93b28ecbe752cc0c9468e1c0 (patch)
tree47b32e7e554e18ec24deb18f942ff4f0014a9c28 /vespalib/src
parent61860ea094ff79c9e8ca6492c04ad351eeb984f9 (diff)
Nexus::run is now static
No change for thread lambdas, but they now get separate Nexus objects.
Diffstat (limited to 'vespalib/src')
-rw-r--r--vespalib/src/tests/nexus/nexus_test.cpp35
-rw-r--r--vespalib/src/tests/rw_spin_lock/rw_spin_lock_test.cpp4
-rw-r--r--vespalib/src/vespa/vespalib/test/nexus.cpp6
-rw-r--r--vespalib/src/vespa/vespalib/test/nexus.h38
4 files changed, 38 insertions, 45 deletions
diff --git a/vespalib/src/tests/nexus/nexus_test.cpp b/vespalib/src/tests/nexus/nexus_test.cpp
index 09f913dccd1..f2fc5b1c218 100644
--- a/vespalib/src/tests/nexus/nexus_test.cpp
+++ b/vespalib/src/tests/nexus/nexus_test.cpp
@@ -11,10 +11,9 @@ TEST(NexusTest, run_void_tasks) {
auto task = [&value](Nexus &) {
value.fetch_add(1, std::memory_order_relaxed);
};
- Nexus ctx(10);
- ctx.run(task);
+ Nexus::run(10, task);
EXPECT_EQ(value, 10);
- ctx.run(task);
+ Nexus::run(10, task);
EXPECT_EQ(value, 20);
}
@@ -24,8 +23,7 @@ TEST(NexusTest, run_value_tasks_select_thread_0) {
value.fetch_add(1, std::memory_order_relaxed);
return ctx.thread_id() + 5;
};
- Nexus ctx(10);
- EXPECT_EQ(ctx.run(task), 5);
+ EXPECT_EQ(Nexus::run(10, task), 5);
EXPECT_EQ(value, 10);
}
@@ -34,8 +32,7 @@ TEST(NexusTest, run_value_tasks_merge_results) {
auto task = [&value](Nexus &) {
return value.fetch_add(1, std::memory_order_relaxed) + 1;
};
- Nexus ctx(10);
- EXPECT_EQ(ctx.run(task, Nexus::merge_sum()), 55);
+ EXPECT_EQ(Nexus::run(10, task, Nexus::merge_sum()), 55);
EXPECT_EQ(value, 10);
}
@@ -46,25 +43,23 @@ TEST(NexusTest, run_inline_voted_loop) {
// continue. After 4 iterations, threads 0,1,2,3,4 vote to exit
// while threads 5,6,7,8 vote to continue. The result is that all
// threads end up doing the loop exactly 4 times.
- auto res = Nexus(9).run([](Nexus &ctx) {
- size_t times = 0;
- for (size_t i = 0; ctx.vote(i < ctx.thread_id()); ++i) {
- ++times;
- }
- return times;
- }, [](auto a, auto b){ EXPECT_EQ(a, b); return a; });
+ auto res = Nexus::run(9, [](Nexus &ctx) {
+ size_t times = 0;
+ for (size_t i = 0; ctx.vote(i < ctx.thread_id()); ++i) {
+ ++times;
+ }
+ return times;
+ }, [](auto a, auto b){ EXPECT_EQ(a, b); return a; });
EXPECT_EQ(res, 4);
}
TEST(NexusTest, run_return_type_decay) {
int value = 3;
auto task = [&](Nexus &)->int&{ return value; };
- Nexus ctx(3);
- auto res = ctx.run(task);
+ auto res = Nexus::run(3, task);
EXPECT_EQ(res, 3);
- EXPECT_EQ(std::addressof(value), std::addressof(task(ctx)));
- using task_res_t = decltype(task(ctx));
- using run_res_t = decltype(ctx.run(task));
+ using task_res_t = decltype(task(std::declval<Nexus&>()));
+ using run_res_t = decltype(Nexus::run(3, task));
static_assert(std::same_as<task_res_t, int&>);
static_assert(std::same_as<run_res_t, int>);
}
@@ -84,7 +79,7 @@ TEST(NexusTest, example_multi_threaded_unit_test) {
EXPECT_EQ(a, 5);
}
};
- Nexus(2).run(work);
+ Nexus::run(2, work);
EXPECT_EQ(a, 5);
EXPECT_EQ(b, 7);
}
diff --git a/vespalib/src/tests/rw_spin_lock/rw_spin_lock_test.cpp b/vespalib/src/tests/rw_spin_lock/rw_spin_lock_test.cpp
index 50621338d8c..feb0453d3f8 100644
--- a/vespalib/src/tests/rw_spin_lock/rw_spin_lock_test.cpp
+++ b/vespalib/src/tests/rw_spin_lock/rw_spin_lock_test.cpp
@@ -187,7 +187,7 @@ BenchmarkResult benchmark_ns(auto &&work, size_t num_threads = 1) {
}
return result;
};
- return Nexus(num_threads).run(entry);
+ return Nexus::run(num_threads, entry);
}
//-----------------------------------------------------------------------------
@@ -283,7 +283,7 @@ void benchmark_lock() {
for (size_t num_threads: {8, 4, 2, 1}) {
if (bench || (bp == 9999 && num_threads == 8)) {
Meets meets(num_threads);
- Nexus(num_threads).run([&](Nexus &ctx) {
+ Nexus::run(num_threads, [&](Nexus &ctx) {
thread_safety_loop(ctx, *lock, *state, meets, bp);
});
}
diff --git a/vespalib/src/vespa/vespalib/test/nexus.cpp b/vespalib/src/vespa/vespalib/test/nexus.cpp
index b5d7b194576..04bd6d26504 100644
--- a/vespalib/src/vespa/vespalib/test/nexus.cpp
+++ b/vespalib/src/vespa/vespalib/test/nexus.cpp
@@ -4,12 +4,6 @@
namespace vespalib::test {
-size_t &
-Nexus::my_thread_id() {
- thread_local size_t thread_id = invalid_thread_id;
- return thread_id;
-}
-
Nexus::~Nexus() = default;
}
diff --git a/vespalib/src/vespa/vespalib/test/nexus.h b/vespalib/src/vespa/vespalib/test/nexus.h
index aeb9337b975..8df840f295d 100644
--- a/vespalib/src/vespa/vespalib/test/nexus.h
+++ b/vespalib/src/vespa/vespalib/test/nexus.h
@@ -23,27 +23,34 @@ concept nexus_thread_entry = requires(Nexus &ctx, T &&entry) {
class Nexus
{
private:
- vespalib::test::ThreadMeets::Vote _vote;
- static size_t &my_thread_id();
+ using vote_t = vespalib::test::ThreadMeets::Vote;
+ vote_t &_vote;
+ size_t _thread_id;
+ Nexus(vote_t &vote, size_t thread_id) noexcept
+ : _vote(vote), _thread_id(thread_id) {}
+ Nexus(Nexus &&) = delete;
+ Nexus(const Nexus &) = delete;
+ Nexus &operator=(Nexus &&) = delete;
+ Nexus &operator=(const Nexus &) = delete;
+ ~Nexus();
public:
- constexpr static size_t invalid_thread_id = -1;
- Nexus(size_t num_threads) noexcept : _vote(num_threads) {}
size_t num_threads() const noexcept { return _vote.size(); }
- size_t thread_id() const noexcept { return my_thread_id(); }
+ size_t thread_id() const noexcept { return _thread_id; }
bool vote(bool my_vote) { return _vote(my_vote); }
void barrier() { REQUIRE_EQ(_vote(true), true); }
struct select_thread_0 {};
constexpr static auto merge_sum() { return [](auto a, auto b){ return a + b; }; }
- auto run(auto &&entry, auto &&merge) requires nexus_thread_entry<decltype(entry)> {
+ static auto run(size_t num_threads, auto &&entry, auto &&merge) requires nexus_thread_entry<decltype(entry)> {
ThreadPool pool;
+ vote_t vote(num_threads);
using result_t = std::decay_t<decltype(entry(std::declval<Nexus&>()))>;
constexpr bool is_void = std::same_as<result_t, void>;
using stored_t = std::conditional<is_void, std::monostate, result_t>::type;
std::mutex lock;
std::optional<stored_t> result;
- auto handle_result = [&](stored_t thread_result) noexcept {
+ auto handle_result = [&](Nexus &ctx, stored_t thread_result) noexcept {
if constexpr (std::same_as<std::decay_t<decltype(merge)>,select_thread_0>) {
- if (thread_id() == 0) {
+ if (ctx.thread_id() == 0) {
result = std::move(thread_result);
}
} else {
@@ -57,16 +64,14 @@ public:
}
};
auto thread_main = [&](size_t thread_id) noexcept {
- size_t old_thread_id = my_thread_id();
- my_thread_id() = thread_id;
+ Nexus ctx(vote, thread_id);
if constexpr (is_void) {
- entry(*this);
+ entry(ctx);
} else {
- handle_result(entry(*this));
+ handle_result(ctx, entry(ctx));
}
- my_thread_id() = old_thread_id;
};
- for (size_t i = 1; i < num_threads(); ++i) {
+ for (size_t i = 1; i < num_threads; ++i) {
pool.start([i,&thread_main]() noexcept { thread_main(i); });
}
thread_main(0);
@@ -75,10 +80,9 @@ public:
return std::move(result).value();
}
}
- auto run(auto &&entry) requires nexus_thread_entry<decltype(entry)> {
- return run(std::forward<decltype(entry)>(entry), select_thread_0{});
+ static auto run(size_t num_threads, auto &&entry) requires nexus_thread_entry<decltype(entry)> {
+ return run(num_threads, std::forward<decltype(entry)>(entry), select_thread_0{});
}
- ~Nexus();
};
}