X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FFutexTest.cpp;h=477a069bf185c382d2ddd8d852492721e37607a0;hb=69433ef3053ca1635c99dc1da712af8784200063;hp=eff4d14b5de15afb8db31f4b0fe98ea6f6d658bf;hpb=f6a8fe63f09913d1784f974845dcfdfef3d5b93e;p=folly.git diff --git a/folly/test/FutexTest.cpp b/folly/test/FutexTest.cpp index eff4d14b..477a069b 100644 --- a/folly/test/FutexTest.cpp +++ b/folly/test/FutexTest.cpp @@ -18,19 +18,28 @@ #include #include +#include +#include #include #include +#include #include -#include #include using namespace folly::detail; using namespace folly::test; +using namespace std; using namespace std::chrono; typedef DeterministicSchedule DSched; +template class Atom> +void run_basic_thread( + Futex& f) { + EXPECT_TRUE(f.futexWait(0)); +} + template class Atom> void run_basic_tests() { Futex f(0); @@ -38,9 +47,7 @@ void run_basic_tests() { EXPECT_FALSE(f.futexWait(1)); EXPECT_EQ(f.futexWake(), 0); - auto thr = DSched::thread([&]{ - EXPECT_TRUE(f.futexWait(0)); - }); + auto thr = DSched::thread(std::bind(run_basic_thread, std::ref(f))); while (f.futexWake() != 1) { std::this_thread::yield(); @@ -49,36 +56,51 @@ void run_basic_tests() { DSched::join(thr); } -template class Atom> -void run_wait_until_tests(); +template class Atom, typename Clock, typename Duration> +void liveClockWaitUntilTests() { + Futex f(0); -template -void stdAtomicWaitUntilTests() { - Futex f(0); - - auto thrA = DSched::thread([&]{ - while (true) { - typename Clock::time_point nowPlus2s = Clock::now() + seconds(2); - auto res = f.futexWaitUntil(0, nowPlus2s); - EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::AWOKEN); - if (res == FutexResult::AWOKEN) { - break; + for (int stress = 0; stress < 1000; ++stress) { + auto fp = &f; // workaround for t5336595 + auto thrA = DSched::thread([fp,stress]{ + while (true) { + const auto deadline = time_point_cast( + Clock::now() + microseconds(1 << (stress % 20))); + const auto res = fp->futexWaitUntil(0, deadline); + EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::AWOKEN); + if (res == FutexResult::AWOKEN) { + break; + } } + }); + + while (f.futexWake() != 1) { + std::this_thread::yield(); } - }); - while (f.futexWake() != 1) { - std::this_thread::yield(); + DSched::join(thrA); } - DSched::join(thrA); + { + const auto start = Clock::now(); + const auto deadline = time_point_cast(start + milliseconds(100)); + EXPECT_EQ(f.futexWaitUntil(0, deadline), FutexResult::TIMEDOUT); + LOG(INFO) << "Futex wait timed out after waiting for " + << duration_cast(Clock::now() - start).count() + << "ms using clock with " << Duration::period::den + << " precision, should be ~100ms"; + } - auto start = Clock::now(); - EXPECT_EQ(f.futexWaitUntil(0, start + milliseconds(100)), - FutexResult::TIMEDOUT); - LOG(INFO) << "Futex wait timed out after waiting for " - << duration_cast(Clock::now() - start).count() - << "ms"; + { + const auto start = Clock::now(); + const auto deadline = time_point_cast( + start - 2 * start.time_since_epoch()); + EXPECT_EQ(f.futexWaitUntil(0, deadline), FutexResult::TIMEDOUT); + LOG(INFO) << "Futex wait with invalid deadline timed out after waiting for " + << duration_cast(Clock::now() - start).count() + << "ms using clock with " << Duration::period::den + << " precision, should be ~0ms"; + } } template @@ -87,14 +109,17 @@ void deterministicAtomicWaitUntilTests() { // Futex wait must eventually fail with either FutexResult::TIMEDOUT or // FutexResult::INTERRUPTED - auto res = f.futexWaitUntil(0, Clock::now() + milliseconds(100)); + const auto res = f.futexWaitUntil(0, Clock::now() + milliseconds(100)); EXPECT_TRUE(res == FutexResult::TIMEDOUT || res == FutexResult::INTERRUPTED); } -template <> -void run_wait_until_tests() { - stdAtomicWaitUntilTests(); - stdAtomicWaitUntilTests(); +template class Atom> +void run_wait_until_tests() { + liveClockWaitUntilTests(); + liveClockWaitUntilTests(); + + typedef duration> decimicroseconds; + liveClockWaitUntilTests(); } template <> @@ -113,7 +138,7 @@ void run_system_clock_test() { struct timespec ts; const int maxIters = 1000; int iter = 0; - uint64_t delta = 10000000 /* 10 ms */; + const uint64_t delta = 10000000 /* 10 ms */; /** 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 @@ -145,15 +170,15 @@ void run_steady_clock_test() { * for the time_points */ EXPECT_TRUE(steady_clock::is_steady); - uint64_t A = duration_cast(steady_clock::now() - .time_since_epoch()).count(); + const uint64_t A = duration_cast(steady_clock::now() + .time_since_epoch()).count(); struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t B = ts.tv_sec * 1000000000ULL + ts.tv_nsec; + const uint64_t B = ts.tv_sec * 1000000000ULL + ts.tv_nsec; - uint64_t C = duration_cast(steady_clock::now() - .time_since_epoch()).count(); + const uint64_t C = duration_cast(steady_clock::now() + .time_since_epoch()).count(); EXPECT_TRUE(A <= B && B <= C); } @@ -172,6 +197,11 @@ TEST(Futex, basic_live) { run_wait_until_tests(); } +TEST(Futex, basic_emulated) { + run_basic_tests(); + run_wait_until_tests(); +} + TEST(Futex, basic_deterministic) { DSched sched(DSched::uniform(0)); run_basic_tests(); @@ -183,4 +213,3 @@ int main(int argc, char ** argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); return RUN_ALL_TESTS(); } -