proxygen
FutexTest.cpp File Reference
#include <folly/detail/Futex.h>
#include <folly/test/DeterministicSchedule.h>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <ratio>
#include <thread>
#include <glog/logging.h>
#include <folly/Chrono.h>
#include <folly/portability/GTest.h>
#include <folly/portability/Time.h>

Go to the source code of this file.

Typedefs

typedef DeterministicSchedule DSched
 

Functions

template<template< typename > class Atom>
void run_basic_thread (Futex< Atom > &f)
 
template<template< typename > class Atom>
void run_basic_tests ()
 
template<template< typename > class Atom, typename Clock , typename Duration >
void liveClockWaitUntilTests ()
 
template<typename Clock >
void deterministicAtomicWaitUntilTests ()
 
template<template< typename > class Atom>
void run_wait_until_tests ()
 
template<>
void run_wait_until_tests< DeterministicAtomic > ()
 
uint64_t diff (uint64_t a, uint64_t b)
 
void run_system_clock_test ()
 
void run_steady_clock_test ()
 
template<template< typename > class Atom>
void run_wake_blocked_test ()
 
 TEST (Futex, clock_source)
 
 TEST (Futex, basic_live)
 
 TEST (Futex, basic_emulated)
 
 TEST (Futex, basic_deterministic)
 
 TEST (Futex, wake_blocked_live)
 
 TEST (Futex, wake_blocked_emulated)
 

Typedef Documentation

Definition at line 38 of file FutexTest.cpp.

Function Documentation

template<typename Clock >
void deterministicAtomicWaitUntilTests ( )

Definition at line 109 of file FutexTest.cpp.

References Atom, EXPECT_TRUE, f, folly::detail::futexWaitUntil(), folly::detail::INTERRUPTED, now(), and folly::detail::TIMEDOUT.

109  {
111 
112  // Futex wait must eventually fail with either FutexResult::TIMEDOUT or
113  // FutexResult::INTERRUPTED
114  const auto res = futexWaitUntil(&f, 0, Clock::now() + milliseconds(100));
115  EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::INTERRUPTED);
116 }
auto f
FutexResult futexWaitUntil(const Futex< MockAtom > *futex, std::uint32_t expected, std::chrono::time_point< Clock, Duration > const &deadline, uint32_t waitMask)
std::chrono::steady_clock::time_point now()
Atom< std::uint32_t > Futex
Definition: Futex.h:51
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
template<template< typename > class Atom, typename Clock , typename Duration >
void liveClockWaitUntilTests ( )

Definition at line 62 of file FutexTest.cpp.

References folly::detail::AWOKEN, count, EXPECT_EQ, EXPECT_TRUE, f, folly::detail::futexWaitUntil(), folly::detail::futexWake(), folly::test::DeterministicSchedule::join(), now(), start, folly::test::DeterministicSchedule::thread(), folly::detail::TIMEDOUT, and folly::fibers::yield().

62  {
63  Futex<Atom> f(0);
64 
65  for (int stress = 0; stress < 1000; ++stress) {
66  auto fp = &f; // workaround for t5336595
67  auto thrA = DSched::thread([fp, stress] {
68  while (true) {
69  const auto deadline = time_point_cast<Duration>(
70  Clock::now() + microseconds(1 << (stress % 20)));
71  const auto res = futexWaitUntil(fp, 0, deadline);
72  EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::AWOKEN);
73  if (res == FutexResult::AWOKEN) {
74  break;
75  }
76  }
77  });
78 
79  while (futexWake(&f) != 1) {
81  }
82 
83  DSched::join(thrA);
84  }
85 
86  {
87  const auto start = Clock::now();
88  const auto deadline = time_point_cast<Duration>(start + milliseconds(100));
89  EXPECT_EQ(futexWaitUntil(&f, 0, deadline), FutexResult::TIMEDOUT);
90  LOG(INFO) << "Futex wait timed out after waiting for "
91  << duration_cast<milliseconds>(Clock::now() - start).count()
92  << "ms using clock with " << Duration::period::den
93  << " precision, should be ~100ms";
94  }
95 
96  {
97  const auto start = Clock::now();
98  const auto deadline =
99  time_point_cast<Duration>(start - 2 * start.time_since_epoch());
100  EXPECT_EQ(futexWaitUntil(&f, 0, deadline), FutexResult::TIMEDOUT);
101  LOG(INFO) << "Futex wait with invalid deadline timed out after waiting for "
102  << duration_cast<milliseconds>(Clock::now() - start).count()
103  << "ms using clock with " << Duration::period::den
104  << " precision, should be ~0ms";
105  }
106 }
auto f
FutexResult futexWaitUntil(const Futex< MockAtom > *futex, std::uint32_t expected, std::chrono::time_point< Clock, Duration > const &deadline, uint32_t waitMask)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::chrono::steady_clock::time_point now()
Atom< std::uint32_t > Futex
Definition: Futex.h:51
static std::thread thread(Func &&func, Args &&...args)
auto start
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
StatsClock::duration Duration
static void join(std::thread &child)
int futexWake(const Futex *futex, int count, uint32_t wakeMask)
Definition: Futex-inl.h:107
template<template< typename > class Atom>
void run_basic_tests ( )

Definition at line 46 of file FutexTest.cpp.

References Atom, folly::netops::bind(), EXPECT_EQ, f, folly::detail::futexWait(), folly::detail::futexWake(), folly::test::DeterministicSchedule::join(), folly::test::DeterministicSchedule::thread(), folly::detail::VALUE_CHANGED, and folly::fibers::yield().

46  {
47  Futex<Atom> f(0);
48 
49  EXPECT_EQ(FutexResult::VALUE_CHANGED, futexWait(&f, 1));
50  EXPECT_EQ(futexWake(&f), 0);
51 
52  auto thr = DSched::thread(std::bind(run_basic_thread<Atom>, std::ref(f)));
53 
54  while (futexWake(&f) != 1) {
56  }
57 
58  DSched::join(thr);
59 }
auto f
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
Atom< std::uint32_t > Futex
Definition: Futex.h:51
static std::thread thread(Func &&func, Args &&...args)
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:76
static void join(std::thread &child)
FutexResult futexWait(const Futex< MockAtom > *futex, uint32_t expected, uint32_t waitMask)
int futexWake(const Futex *futex, int count, uint32_t wakeMask)
Definition: Futex-inl.h:107
template<template< typename > class Atom>
void run_basic_thread ( Futex< Atom > &  f)

Definition at line 41 of file FutexTest.cpp.

References Atom, folly::detail::AWOKEN, EXPECT_EQ, and folly::detail::futexWait().

41  {
42  EXPECT_EQ(FutexResult::AWOKEN, futexWait(&f, 0));
43 }
auto f
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
FutexResult futexWait(const Futex< MockAtom > *futex, uint32_t expected, uint32_t waitMask)
void run_steady_clock_test ( )

Definition at line 172 of file FutexTest.cpp.

References Atom, B, C, folly::chrono::clock_gettime, count, EXPECT_TRUE, now(), and uint64_t.

Referenced by TEST().

172  {
173  /* Test to verify that steady_clock uses clock_gettime(CLOCK_MONOTONIC, ...)
174  * for the time_points */
175  EXPECT_TRUE(steady_clock::is_steady);
176 
177  const uint64_t A =
178  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
179  .count();
180 
181  struct timespec ts;
182  clock_gettime(CLOCK_MONOTONIC, &ts);
183  const uint64_t B = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
184 
185  const uint64_t C =
186  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
187  .count();
188  EXPECT_TRUE(A <= B && B <= C);
189 }
std::unique_ptr< int > A
int(* clock_gettime)(clockid_t, timespec *ts)
std::chrono::steady_clock::time_point now()
#define C(name, bit)
Definition: CpuId.h:204
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define B(name, bit)
Definition: CpuId.h:178
void run_system_clock_test ( )

The following loop is only to make the test more robust in the presence of clock adjustments that can occur. We just run the loop maxIter times and expect with very high probability that there will be atleast one iteration of the test during which clock adjustments > delta have not occurred.

Definition at line 139 of file FutexTest.cpp.

References a, b, c, folly::chrono::clock_gettime, count, diff(), EXPECT_TRUE, now(), and uint64_t.

Referenced by TEST().

139  {
140  /* Test to verify that system_clock uses clock_gettime(CLOCK_REALTIME, ...)
141  * for the time_points */
142  struct timespec ts;
143  const int maxIters = 1000;
144  int iter = 0;
145  const uint64_t delta = 10000000 /* 10 ms */;
146 
151  while (iter < maxIters) {
152  uint64_t a =
153  duration_cast<nanoseconds>(system_clock::now().time_since_epoch())
154  .count();
155 
156  clock_gettime(CLOCK_REALTIME, &ts);
157  uint64_t b = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
158 
159  uint64_t c =
160  duration_cast<nanoseconds>(system_clock::now().time_since_epoch())
161  .count();
162 
163  if (diff(a, b) <= delta && diff(b, c) <= delta && diff(a, c) <= 2 * delta) {
164  /* Success! system_clock uses CLOCK_REALTIME for time_points */
165  break;
166  }
167  iter++;
168  }
169  EXPECT_TRUE(iter < maxIters);
170 }
int(* clock_gettime)(clockid_t, timespec *ts)
char b
std::chrono::steady_clock::time_point now()
char a
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
uint64_t diff(uint64_t a, uint64_t b)
Definition: FutexTest.cpp:135
char c
template<template< typename > class Atom>
void run_wait_until_tests ( )

Definition at line 119 of file FutexTest.cpp.

119  {
120  liveClockWaitUntilTests<Atom, system_clock, system_clock::duration>();
121  liveClockWaitUntilTests<Atom, steady_clock, steady_clock::duration>();
122  liveClockWaitUntilTests<Atom, steady_clock, coarse_steady_clock::duration>();
123 
124  typedef duration<int64_t, std::ratio<1, 10000000>> decimicroseconds;
125  liveClockWaitUntilTests<Atom, system_clock, decimicroseconds>();
126 }
template<>
void run_wait_until_tests< DeterministicAtomic > ( )

Definition at line 129 of file FutexTest.cpp.

Referenced by TEST().

129  {
130  deterministicAtomicWaitUntilTests<system_clock>();
131  deterministicAtomicWaitUntilTests<steady_clock>();
132  deterministicAtomicWaitUntilTests<coarse_steady_clock>();
133 }
template<template< typename > class Atom>
void run_wake_blocked_test ( )

Definition at line 192 of file FutexTest.cpp.

References folly::detail::AWOKEN, f, folly::detail::futexWait(), folly::detail::futexWake(), folly::test::DeterministicSchedule::join(), folly::detail::success, and folly::test::DeterministicSchedule::thread().

192  {
193  for (auto delay = std::chrono::milliseconds(1);; delay *= 2) {
194  bool success = false;
195  Futex<Atom> f(0);
196  auto thr = DSched::thread(
197  [&] { success = FutexResult::AWOKEN == futexWait(&f, 0); });
198  /* sleep override */ std::this_thread::sleep_for(delay);
199  f.store(1);
200  futexWake(&f, 1);
201  DSched::join(thr);
202  LOG(INFO) << "delay=" << delay.count() << "_ms, success=" << success;
203  if (success) {
204  break;
205  }
206  }
207 }
auto f
Atom< std::uint32_t > Futex
Definition: Futex.h:51
static std::thread thread(Func &&func, Args &&...args)
static void join(std::thread &child)
FutexResult futexWait(const Futex< MockAtom > *futex, uint32_t expected, uint32_t waitMask)
int futexWake(const Futex *futex, int count, uint32_t wakeMask)
Definition: Futex-inl.h:107
TEST ( Futex  ,
clock_source   
)

Definition at line 209 of file FutexTest.cpp.

References run_steady_clock_test(), run_system_clock_test(), and value.

209  {
211 
212  /* On some systems steady_clock is just an alias for system_clock. So,
213  * we must skip run_steady_clock_test if the two clocks are the same. */
216  }
217 }
static const char *const value
Definition: Conv.cpp:50
void run_system_clock_test()
Definition: FutexTest.cpp:139
void run_steady_clock_test()
Definition: FutexTest.cpp:172
TEST ( Futex  ,
basic_live   
)

Definition at line 219 of file FutexTest.cpp.

219  {
220  run_basic_tests<std::atomic>();
221  run_wait_until_tests<std::atomic>();
222 }
TEST ( Futex  ,
basic_emulated   
)

Definition at line 224 of file FutexTest.cpp.

224  {
225  run_basic_tests<EmulatedFutexAtomic>();
226  run_wait_until_tests<EmulatedFutexAtomic>();
227 }
TEST ( Futex  ,
basic_deterministic   
)

Definition at line 229 of file FutexTest.cpp.

References run_wait_until_tests< DeterministicAtomic >(), and folly::test::DeterministicSchedule::uniform().

229  {
230  DSched sched(DSched::uniform(0));
231  run_basic_tests<DeterministicAtomic>();
233 }
static std::function< size_t(size_t)> uniform(uint64_t seed)
void run_wait_until_tests< DeterministicAtomic >()
Definition: FutexTest.cpp:129
TEST ( Futex  ,
wake_blocked_live   
)

Definition at line 235 of file FutexTest.cpp.

235  {
236  run_wake_blocked_test<std::atomic>();
237 }
TEST ( Futex  ,
wake_blocked_emulated   
)

Definition at line 239 of file FutexTest.cpp.

239  {
240  run_wake_blocked_test<EmulatedFutexAtomic>();
241 }