]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/common/test_fair_mutex.cc
import ceph 16.2.7
[ceph.git] / ceph / src / test / common / test_fair_mutex.cc
CommitLineData
a4b75251
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2
3#include <array>
4#include <mutex>
5#include <numeric>
6#include <future>
7#include <gtest/gtest.h>
8#include "common/fair_mutex.h"
9
10TEST(FairMutex, simple)
11{
12 ceph::fair_mutex mutex{"fair::simple"};
13 {
14 std::unique_lock lock{mutex};
15 ASSERT_TRUE(mutex.is_locked());
16 // fair_mutex does not recursive ownership semantics
17 ASSERT_FALSE(mutex.try_lock());
18 }
19 // re-acquire the lock
20 {
21 std::unique_lock lock{mutex};
22 ASSERT_TRUE(mutex.is_locked());
23 }
24 ASSERT_FALSE(mutex.is_locked());
25}
26
27TEST(FairMutex, fair)
28{
29 // waiters are queued in FIFO order, and they are woken up in the same order
30 // we have a marathon participated by multiple teams:
31 // - each team is represented by a thread.
32 // - each team should have equal chance of being selected and scoring, assuming
33 // the runners in each team are distributed evenly in the waiting queue.
34 ceph::fair_mutex mutex{"fair::fair"};
35 const int NR_TEAMS = 2;
36 std::array<unsigned, NR_TEAMS> scoreboard{0, 0};
37 const int NR_ROUNDS = 512;
38 auto play = [&](int team) {
39 for (int i = 0; i < NR_ROUNDS; i++) {
40 std::unique_lock lock{mutex};
41 // pretent that i am running.. and it takes time
42 std::this_thread::sleep_for(std::chrono::microseconds(20));
43 // score!
44 scoreboard[team]++;
45 // fair?
46 unsigned total = std::accumulate(scoreboard.begin(),
47 scoreboard.end(),
48 0);
49 for (unsigned score : scoreboard) {
50 if (total < NR_ROUNDS) {
51 // not quite statistically significant. to reduce the false positive,
52 // just consider it fair
53 continue;
54 }
55 // check if any team is donimating the game.
56 unsigned avg = total / scoreboard.size();
57 // leave at least half of the average to other teams
58 ASSERT_LE(score, total - avg / 2);
59 // don't treat myself too bad
60 ASSERT_GT(score, avg / 2);
61 };
62 }
63 };
64 std::array<std::future<void>, NR_TEAMS> completed;
65 for (int team = 0; team < NR_TEAMS; team++) {
66 completed[team] = std::async(std::launch::async, play, team);
67 }
68}