diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/test/common/test_fair_mutex.cc | |
parent | Initial commit. (diff) | |
download | ceph-upstream/16.2.11+ds.tar.xz ceph-upstream/16.2.11+ds.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/test/common/test_fair_mutex.cc | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/test/common/test_fair_mutex.cc b/src/test/common/test_fair_mutex.cc new file mode 100644 index 000000000..10ba835a2 --- /dev/null +++ b/src/test/common/test_fair_mutex.cc @@ -0,0 +1,68 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- + +#include <array> +#include <mutex> +#include <numeric> +#include <future> +#include <gtest/gtest.h> +#include "common/fair_mutex.h" + +TEST(FairMutex, simple) +{ + ceph::fair_mutex mutex{"fair::simple"}; + { + std::unique_lock lock{mutex}; + ASSERT_TRUE(mutex.is_locked()); + // fair_mutex does not recursive ownership semantics + ASSERT_FALSE(mutex.try_lock()); + } + // re-acquire the lock + { + std::unique_lock lock{mutex}; + ASSERT_TRUE(mutex.is_locked()); + } + ASSERT_FALSE(mutex.is_locked()); +} + +TEST(FairMutex, fair) +{ + // waiters are queued in FIFO order, and they are woken up in the same order + // we have a marathon participated by multiple teams: + // - each team is represented by a thread. + // - each team should have equal chance of being selected and scoring, assuming + // the runners in each team are distributed evenly in the waiting queue. + ceph::fair_mutex mutex{"fair::fair"}; + const int NR_TEAMS = 2; + std::array<unsigned, NR_TEAMS> scoreboard{0, 0}; + const int NR_ROUNDS = 512; + auto play = [&](int team) { + for (int i = 0; i < NR_ROUNDS; i++) { + std::unique_lock lock{mutex}; + // pretent that i am running.. and it takes time + std::this_thread::sleep_for(std::chrono::microseconds(20)); + // score! + scoreboard[team]++; + // fair? + unsigned total = std::accumulate(scoreboard.begin(), + scoreboard.end(), + 0); + for (unsigned score : scoreboard) { + if (total < NR_ROUNDS) { + // not quite statistically significant. to reduce the false positive, + // just consider it fair + continue; + } + // check if any team is donimating the game. + unsigned avg = total / scoreboard.size(); + // leave at least half of the average to other teams + ASSERT_LE(score, total - avg / 2); + // don't treat myself too bad + ASSERT_GT(score, avg / 2); + }; + } + }; + std::array<std::future<void>, NR_TEAMS> completed; + for (int team = 0; team < NR_TEAMS; team++) { + completed[team] = std::async(std::launch::async, play, team); + } +} |