From: Yedidya Feldblum Date: Sun, 10 Dec 2017 20:39:24 +0000 (-0800) Subject: Remove multi-poster support from Baton X-Git-Tag: v2017.12.11.00^0 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=712b8b8de747960ceeceedfd3a18ee23a0c03a80 Remove multi-poster support from Baton Summary: [Folly] Remove multi-poster support from `Baton`. Code which needs multi-poster support may use `SaturatingSemaphore` instead. Reviewed By: magedm Differential Revision: D6529661 fbshipit-source-id: d9dc053ca984ef3a404e9361910b0044817d4905 --- diff --git a/folly/synchronization/Baton.h b/folly/synchronization/Baton.h index ef871252..379f9021 100644 --- a/folly/synchronization/Baton.h +++ b/folly/synchronization/Baton.h @@ -29,22 +29,16 @@ namespace folly { -/// A Baton allows a thread to block once and be awoken. The single -/// poster version (with SinglePoster == true) captures a single -/// handoff, and during its lifecycle (from construction/reset to -/// destruction/reset) a baton must either be post()ed and wait()ed +/// A Baton allows a thread to block once and be awoken. Captures a +/// single handoff, and during its lifecycle (from construction/reset +/// to destruction/reset) a baton must either be post()ed and wait()ed /// exactly once each, or not at all. /// -/// The multi-poster version (SinglePoster == false) allows multiple -/// concurrent handoff attempts, the first of which completes the -/// handoff and the rest if any are idempotent. -/// /// Baton includes no internal padding, and is only 4 bytes in size. /// Any alignment or padding to avoid false sharing is up to the user. /// -/// This is basically a stripped-down semaphore that supports (only a -/// single call to sem_post, when SinglePoster == true) and a single -/// call to sem_wait. +/// This is basically a stripped-down semaphore that supports only a +/// single call to sem_post and a single call to sem_wait. /// /// The non-blocking version (Blocking == false) provides more speed /// by using only load acquire and store release operations in the @@ -58,7 +52,6 @@ namespace folly { /// catch race conditions ahead of time. template < template class Atom = std::atomic, - bool SinglePoster = true, // single vs multiple posters bool Blocking = true> // blocking vs spinning struct Baton { constexpr Baton() : state_(INIT) {} @@ -130,65 +123,24 @@ struct Baton { /// Blocking versions /// - if (SinglePoster) { - /// Single poster version - /// - uint32_t before = state_.load(std::memory_order_acquire); + uint32_t before = state_.load(std::memory_order_acquire); - assert(before == INIT || before == WAITING || before == TIMED_OUT); + assert(before == INIT || before == WAITING || before == TIMED_OUT); - if (before == INIT && - state_.compare_exchange_strong(before, EARLY_DELIVERY)) { - return; - } - - assert(before == WAITING || before == TIMED_OUT); + if (before == INIT && + state_.compare_exchange_strong(before, EARLY_DELIVERY)) { + return; + } - if (before == TIMED_OUT) { - return; - } + assert(before == WAITING || before == TIMED_OUT); - assert(before == WAITING); - state_.store(LATE_DELIVERY, std::memory_order_release); - state_.futexWake(1); - } else { - /// Multi-poster version - /// - while (true) { - uint32_t before = state_.load(std::memory_order_acquire); - - if (before == INIT && - state_.compare_exchange_strong(before, EARLY_DELIVERY)) { - return; - } - - if (before == TIMED_OUT) { - return; - } - - if (before == EARLY_DELIVERY || before == LATE_DELIVERY) { - // The reason for not simply returning (without the following - // atomic operation) is to avoid the following case: - // - // T1: T2: T3: - // local1.post(); local2.post(); global.wait(); - // global.post(); global.post(); local1.try_wait() == true; - // local2.try_wait() == false; - // - if (state_.fetch_add(0) != before) { - continue; - } - return; - } - - assert(before == WAITING); - if (!state_.compare_exchange_weak(before, LATE_DELIVERY)) { - continue; - } - state_.futexWake(1); - return; - } + if (before == TIMED_OUT) { + return; } + + assert(before == WAITING); + state_.store(LATE_DELIVERY, std::memory_order_release); + state_.futexWake(1); } /// Waits until post() has been called in the current Baton lifetime. diff --git a/folly/synchronization/test/BatonBenchmark.cpp b/folly/synchronization/test/BatonBenchmark.cpp index 25126282..1c3c8846 100644 --- a/folly/synchronization/test/BatonBenchmark.cpp +++ b/folly/synchronization/test/BatonBenchmark.cpp @@ -19,8 +19,6 @@ #include #include -#include -#include #include #include #include @@ -31,38 +29,22 @@ using folly::detail::EmulatedFutexAtomic; typedef DeterministicSchedule DSched; -BENCHMARK(baton_pingpong_single_poster_blocking, iters) { - run_pingpong_test(iters); +BENCHMARK(baton_pingpong_blocking, iters) { + run_pingpong_test(iters); } -BENCHMARK(baton_pingpong_multi_poster_blocking, iters) { - run_pingpong_test(iters); -} - -BENCHMARK(baton_pingpong_single_poster_nonblocking, iters) { - run_pingpong_test(iters); -} - -BENCHMARK(baton_pingpong_multi_poster_nonblocking, iters) { - run_pingpong_test(iters); +BENCHMARK(baton_pingpong_nonblocking, iters) { + run_pingpong_test(iters); } BENCHMARK_DRAW_LINE() -BENCHMARK(baton_pingpong_emulated_futex_single_poster_blocking, iters) { - run_pingpong_test(iters); -} - -BENCHMARK(baton_pingpong_emulated_futex_multi_poster_blocking, iters) { - run_pingpong_test(iters); -} - -BENCHMARK(baton_pingpong_emulated_futex_single_poster_nonblocking, iters) { - run_pingpong_test(iters); +BENCHMARK(baton_pingpong_emulated_futex_blocking, iters) { + run_pingpong_test(iters); } -BENCHMARK(baton_pingpong_emulated_futex_multi_poster_nonblocking, iters) { - run_pingpong_test(iters); +BENCHMARK(baton_pingpong_emulated_futex_nonblocking, iters) { + run_pingpong_test(iters); } BENCHMARK_DRAW_LINE() @@ -93,12 +75,7 @@ BENCHMARK(posix_sem_pingpong, iters) { // to the required futex calls for the blocking case int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); gflags::ParseCommandLineFlags(&argc, &argv, true); - - auto rv = RUN_ALL_TESTS(); - if (!rv && FLAGS_benchmark) { - folly::runBenchmarks(); - } - return rv; + folly::runBenchmarks(); + return 0; } diff --git a/folly/synchronization/test/BatonTest.cpp b/folly/synchronization/test/BatonTest.cpp index 2e6f5164..955f29bc 100644 --- a/folly/synchronization/test/BatonTest.cpp +++ b/folly/synchronization/test/BatonTest.cpp @@ -28,258 +28,92 @@ using folly::detail::EmulatedFutexAtomic; /// Basic test -TEST(Baton, basic_single_poster_blocking) { - run_basic_test(); - run_basic_test(); - run_basic_test(); +TEST(Baton, basic_blocking) { + run_basic_test(); + run_basic_test(); + run_basic_test(); } -TEST(Baton, basic_single_poster_nonblocking) { - run_basic_test(); - run_basic_test(); - run_basic_test(); -} - -TEST(Baton, basic_multi_poster_blocking) { - run_basic_test(); -} - -TEST(Baton, basic_multi_poster_nonblocking) { - run_basic_test(); +TEST(Baton, basic_nonblocking) { + run_basic_test(); + run_basic_test(); + run_basic_test(); } /// Ping pong tests -TEST(Baton, pingpong_single_poster_blocking) { - DSched sched(DSched::uniform(0)); - - run_pingpong_test(1000); -} - -TEST(Baton, pingpong_single_poster_nonblocking) { +TEST(Baton, pingpong_blocking) { DSched sched(DSched::uniform(0)); - run_pingpong_test(1000); + run_pingpong_test(1000); } -TEST(Baton, pingpong_multi_poster_blocking) { +TEST(Baton, pingpong_nonblocking) { DSched sched(DSched::uniform(0)); - run_pingpong_test(1000); -} - -TEST(Baton, pingpong_multi_poster_nonblocking) { - DSched sched(DSched::uniform(0)); - - run_pingpong_test(1000); + run_pingpong_test(1000); } /// Timed wait tests - Nonblocking Baton does not support timed_wait() // Timed wait basic system clock tests -TEST(Baton, timed_wait_basic_system_clock_single_poster) { - run_basic_timed_wait_tests(); - run_basic_timed_wait_tests< - EmulatedFutexAtomic, - std::chrono::system_clock, - true>(); - run_basic_timed_wait_tests< - DeterministicAtomic, - std::chrono::system_clock, - true>(); -} - -TEST(Baton, timed_wait_basic_system_clock_multi_poster) { - run_basic_timed_wait_tests(); - run_basic_timed_wait_tests< - EmulatedFutexAtomic, - std::chrono::system_clock, - false>(); - run_basic_timed_wait_tests< - DeterministicAtomic, - std::chrono::system_clock, - false>(); +TEST(Baton, timed_wait_basic_system_clock) { + run_basic_timed_wait_tests(); + run_basic_timed_wait_tests(); + run_basic_timed_wait_tests(); } // Timed wait timeout system clock tests -TEST(Baton, timed_wait_timeout_system_clock_single_poster) { - run_timed_wait_tmo_tests(); - run_timed_wait_tmo_tests< - EmulatedFutexAtomic, - std::chrono::system_clock, - true>(); - run_timed_wait_tmo_tests< - DeterministicAtomic, - std::chrono::system_clock, - true>(); -} - -TEST(Baton, timed_wait_timeout_system_clock_multi_poster) { - run_timed_wait_tmo_tests(); - run_timed_wait_tmo_tests< - EmulatedFutexAtomic, - std::chrono::system_clock, - false>(); - run_timed_wait_tmo_tests< - DeterministicAtomic, - std::chrono::system_clock, - false>(); +TEST(Baton, timed_wait_timeout_system_clock) { + run_timed_wait_tmo_tests(); + run_timed_wait_tmo_tests(); + run_timed_wait_tmo_tests(); } // Timed wait regular system clock tests -TEST(Baton, timed_wait_system_clock_single_poster) { - run_timed_wait_regular_test(); - run_timed_wait_regular_test< - EmulatedFutexAtomic, - std::chrono::system_clock, - true>(); - run_timed_wait_regular_test< - DeterministicAtomic, - std::chrono::system_clock, - true>(); -} - -TEST(Baton, timed_wait_system_clock_multi_poster) { - run_timed_wait_regular_test(); - run_timed_wait_regular_test< - EmulatedFutexAtomic, - std::chrono::system_clock, - false>(); - run_timed_wait_regular_test< - DeterministicAtomic, - std::chrono::system_clock, - false>(); +TEST(Baton, timed_wait_system_clock) { + run_timed_wait_regular_test(); + run_timed_wait_regular_test(); + run_timed_wait_regular_test(); } // Timed wait basic steady clock tests -TEST(Baton, timed_wait_basic_steady_clock_single_poster) { - run_basic_timed_wait_tests(); - run_basic_timed_wait_tests< - EmulatedFutexAtomic, - std::chrono::steady_clock, - true>(); - run_basic_timed_wait_tests< - DeterministicAtomic, - std::chrono::steady_clock, - true>(); -} - -TEST(Baton, timed_wait_basic_steady_clock_multi_poster) { - run_basic_timed_wait_tests(); - run_basic_timed_wait_tests< - EmulatedFutexAtomic, - std::chrono::steady_clock, - false>(); - run_basic_timed_wait_tests< - DeterministicAtomic, - std::chrono::steady_clock, - false>(); +TEST(Baton, timed_wait_basic_steady_clock) { + run_basic_timed_wait_tests(); + run_basic_timed_wait_tests(); + run_basic_timed_wait_tests(); } // Timed wait timeout steady clock tests -TEST(Baton, timed_wait_timeout_steady_clock_single_poster) { - run_timed_wait_tmo_tests(); - run_timed_wait_tmo_tests< - EmulatedFutexAtomic, - std::chrono::steady_clock, - true>(); - run_timed_wait_tmo_tests< - DeterministicAtomic, - std::chrono::steady_clock, - true>(); -} - -TEST(Baton, timed_wait_timeout_steady_clock_multi_poster) { - run_timed_wait_tmo_tests(); - run_timed_wait_tmo_tests< - EmulatedFutexAtomic, - std::chrono::steady_clock, - false>(); - run_timed_wait_tmo_tests< - DeterministicAtomic, - std::chrono::steady_clock, - false>(); +TEST(Baton, timed_wait_timeout_steady_clock) { + run_timed_wait_tmo_tests(); + run_timed_wait_tmo_tests(); + run_timed_wait_tmo_tests(); } // Timed wait regular steady clock tests -TEST(Baton, timed_wait_steady_clock_single_poster) { - run_timed_wait_regular_test(); - run_timed_wait_regular_test< - EmulatedFutexAtomic, - std::chrono::steady_clock, - true>(); - run_timed_wait_regular_test< - DeterministicAtomic, - std::chrono::steady_clock, - true>(); -} - -TEST(Baton, timed_wait_steady_clock_multi_poster) { - run_timed_wait_regular_test(); - run_timed_wait_regular_test< - EmulatedFutexAtomic, - std::chrono::steady_clock, - false>(); - run_timed_wait_regular_test< - DeterministicAtomic, - std::chrono::steady_clock, - false>(); +TEST(Baton, timed_wait_steady_clock) { + run_timed_wait_regular_test(); + run_timed_wait_regular_test(); + run_timed_wait_regular_test(); } /// Try wait tests -TEST(Baton, try_wait_single_poster_blocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); -} - -TEST(Baton, try_wait_single_poster_nonblocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); -} - -TEST(Baton, try_wait_multi_poster_blocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); -} - -TEST(Baton, try_wait_multi_poster_nonblocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); -} - -/// Multi-producer tests - -TEST(Baton, multi_producer_single_poster_blocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); -} - -TEST(Baton, multi_producer_single_poster_nonblocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); -} - -TEST(Baton, multi_producer_multi_poster_blocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); +TEST(Baton, try_wait_blocking) { + run_try_wait_tests(); + run_try_wait_tests(); + run_try_wait_tests(); } -TEST(Baton, multi_producer_multi_poster_nonblocking) { - run_try_wait_tests(); - run_try_wait_tests(); - run_try_wait_tests(); +TEST(Baton, try_wait_nonblocking) { + run_try_wait_tests(); + run_try_wait_tests(); + run_try_wait_tests(); } diff --git a/folly/synchronization/test/BatonTestHelpers.h b/folly/synchronization/test/BatonTestHelpers.h index 6e242e2a..1f07a2af 100644 --- a/folly/synchronization/test/BatonTestHelpers.h +++ b/folly/synchronization/test/BatonTestHelpers.h @@ -25,16 +25,16 @@ namespace test { typedef DeterministicSchedule DSched; -template