From: James Sedgwick Date: Thu, 19 Oct 2017 21:08:04 +0000 (-0700) Subject: move CallOnce to synchronization/ X-Git-Tag: v2017.10.23.00~9 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=18172db622389a6401ce731cc25a0870baa816fa;p=folly.git move CallOnce to synchronization/ Summary: as above Reviewed By: knekritz Differential Revision: D6088687 fbshipit-source-id: 0efbb7f5fa33b5f553c0c2019658370fc6e8613f --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 68fdc288..e41ba08d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -475,6 +475,9 @@ if (BUILD_TESTS) TEST timeseries_histogram_test SOURCES TimeseriesHistogramTest.cpp TEST timeseries_test SOURCES TimeseriesTest.cpp + DIRECTORY synchronization/test/ + TEST call_once_test SOURCES CallOnceTest.cpp + DIRECTORY test/ TEST ahm_int_stress_test SOURCES AHMIntStressTest.cpp TEST arena_test SOURCES ArenaTest.cpp @@ -492,7 +495,6 @@ if (BUILD_TESTS) TEST bit_iterator_test SOURCES BitIteratorTest.cpp TEST bits_test SOURCES BitsTest.cpp TEST cacheline_padded_test SOURCES CachelinePaddedTest.cpp - TEST call_once_test SOURCES CallOnceTest.cpp TEST checksum_test SOURCES ChecksumTest.cpp TEST clock_gettime_wrappers_test SOURCES ClockGettimeWrappersTest.cpp TEST concurrent_skip_list_test SOURCES ConcurrentSkipListTest.cpp diff --git a/folly/CallOnce.h b/folly/CallOnce.h deleted file mode 100644 index 4dd06941..00000000 --- a/folly/CallOnce.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2017 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Drop-in replacement for std::call_once() with a fast path, which the GCC - * implementation lacks. The tradeoff is a slightly larger `once_flag' struct - * (8 bytes vs 4 bytes with GCC on Linux/x64). - * - * $ call_once_test --benchmark --bm_min_iters=100000000 --threads=16 - * ============================================================================ - * folly/test/CallOnceTest.cpp relative time/iter iters/s - * ============================================================================ - * StdCallOnceBench 3.54ns 282.82M - * FollyCallOnceBench 698.48ps 1.43G - * ============================================================================ - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace folly { - -class once_flag { - public: - constexpr once_flag() noexcept = default; - once_flag(const once_flag&) = delete; - once_flag& operator=(const once_flag&) = delete; - - template - friend void call_once(once_flag& flag, Callable&& f, Args&&... args); - template - friend void call_once_impl_no_inline(once_flag& flag, - Callable&& f, - Args&&... args); - - private: - std::atomic called_{false}; - folly::SharedMutex mutex_; -}; - -template -void FOLLY_ALWAYS_INLINE -call_once(once_flag& flag, Callable&& f, Args&&... args) { - if (LIKELY(flag.called_.load(std::memory_order_acquire))) { - return; - } - call_once_impl_no_inline( - flag, std::forward(f), std::forward(args)...); -} - -// Implementation detail: out-of-line slow path -template -void FOLLY_NOINLINE -call_once_impl_no_inline(once_flag& flag, Callable&& f, Args&&... args) { - std::lock_guard lg(flag.mutex_); - if (flag.called_) { - return; - } - - std::forward(f)(std::forward(args)...); - - flag.called_.store(true, std::memory_order_release); -} -} diff --git a/folly/Makefile.am b/folly/Makefile.am index 2223da74..344dc3ae 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -44,7 +44,6 @@ nobase_follyinclude_HEADERS = \ Benchmark.h \ Bits.h \ CachelinePadded.h \ - CallOnce.h \ Chrono.h \ ClockGettimeWrappers.h \ ConcurrentSkipList.h \ @@ -419,6 +418,7 @@ nobase_follyinclude_HEADERS = \ stats/MultiLevelTimeSeries.h \ stats/TimeseriesHistogram-defs.h \ stats/TimeseriesHistogram.h \ + synchronization/CallOnce.h \ stop_watch.h \ String.h \ String-inl.h \ diff --git a/folly/Random.cpp b/folly/Random.cpp index 524b9d06..f643fb52 100644 --- a/folly/Random.cpp +++ b/folly/Random.cpp @@ -21,13 +21,13 @@ #include #include -#include #include #include #include #include #include #include +#include #include #ifdef _MSC_VER diff --git a/folly/io/async/EventBase.h b/folly/io/async/EventBase.h index 670d6af6..1454c847 100644 --- a/folly/io/async/EventBase.h +++ b/folly/io/async/EventBase.h @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include namespace folly { diff --git a/folly/synchronization/CallOnce.h b/folly/synchronization/CallOnce.h new file mode 100644 index 00000000..4dd06941 --- /dev/null +++ b/folly/synchronization/CallOnce.h @@ -0,0 +1,84 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Drop-in replacement for std::call_once() with a fast path, which the GCC + * implementation lacks. The tradeoff is a slightly larger `once_flag' struct + * (8 bytes vs 4 bytes with GCC on Linux/x64). + * + * $ call_once_test --benchmark --bm_min_iters=100000000 --threads=16 + * ============================================================================ + * folly/test/CallOnceTest.cpp relative time/iter iters/s + * ============================================================================ + * StdCallOnceBench 3.54ns 282.82M + * FollyCallOnceBench 698.48ps 1.43G + * ============================================================================ + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace folly { + +class once_flag { + public: + constexpr once_flag() noexcept = default; + once_flag(const once_flag&) = delete; + once_flag& operator=(const once_flag&) = delete; + + template + friend void call_once(once_flag& flag, Callable&& f, Args&&... args); + template + friend void call_once_impl_no_inline(once_flag& flag, + Callable&& f, + Args&&... args); + + private: + std::atomic called_{false}; + folly::SharedMutex mutex_; +}; + +template +void FOLLY_ALWAYS_INLINE +call_once(once_flag& flag, Callable&& f, Args&&... args) { + if (LIKELY(flag.called_.load(std::memory_order_acquire))) { + return; + } + call_once_impl_no_inline( + flag, std::forward(f), std::forward(args)...); +} + +// Implementation detail: out-of-line slow path +template +void FOLLY_NOINLINE +call_once_impl_no_inline(once_flag& flag, Callable&& f, Args&&... args) { + std::lock_guard lg(flag.mutex_); + if (flag.called_) { + return; + } + + std::forward(f)(std::forward(args)...); + + flag.called_.store(true, std::memory_order_release); +} +} diff --git a/folly/synchronization/test/CallOnceBenchmark.cpp b/folly/synchronization/test/CallOnceBenchmark.cpp new file mode 100644 index 00000000..f85b23b5 --- /dev/null +++ b/folly/synchronization/test/CallOnceBenchmark.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include + +#include + +DEFINE_int32(threads, 16, "benchmark concurrency"); + +template +void bm_impl(CallOnceFunc&& fn, int64_t iters) { + std::deque threads; + for (int i = 0; i < FLAGS_threads; ++i) { + threads.emplace_back([&fn, iters] { + for (int64_t j = 0; j < iters; ++j) { + fn(); + } + }); + } + for (std::thread& t : threads) { + t.join(); + } +} + +BENCHMARK(StdCallOnceBench, iters) { + std::once_flag flag; + int out = 0; + bm_impl([&] { std::call_once(flag, [&] { ++out; }); }, iters); + CHECK_EQ(1, out); +} + +BENCHMARK(FollyCallOnceBench, iters) { + folly::once_flag flag; + int out = 0; + bm_impl([&] { folly::call_once(flag, [&] { ++out; }); }, iters); + CHECK_EQ(1, out); +} + +int main(int argc, char** argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + folly::runBenchmarks(); + return 0; +} diff --git a/folly/synchronization/test/CallOnceTest.cpp b/folly/synchronization/test/CallOnceTest.cpp new file mode 100644 index 00000000..81bcbe55 --- /dev/null +++ b/folly/synchronization/test/CallOnceTest.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +DEFINE_int32(threads, 16, "benchmark concurrency"); + +template +void bm_impl(CallOnceFunc&& fn, int64_t iters) { + std::deque threads; + for (int i = 0; i < FLAGS_threads; ++i) { + threads.emplace_back([&fn, iters] { + for (int64_t j = 0; j < iters; ++j) { + fn(); + } + }); + } + for (std::thread& t : threads) { + t.join(); + } +} + +TEST(FollyCallOnce, Simple) { + folly::once_flag flag; + auto fn = [&](int* outp) { ++*outp; }; + int out = 0; + folly::call_once(flag, fn, &out); + folly::call_once(flag, fn, &out); + ASSERT_EQ(1, out); +} + +TEST(FollyCallOnce, Exception) { + struct ExpectedException {}; + folly::once_flag flag; + size_t numCalls = 0; + EXPECT_THROW( + folly::call_once( + flag, + [&] { + ++numCalls; + throw ExpectedException(); + }), + ExpectedException); + EXPECT_EQ(1, numCalls); + folly::call_once(flag, [&] { ++numCalls; }); + EXPECT_EQ(2, numCalls); +} + +TEST(FollyCallOnce, Stress) { + for (int i = 0; i < 100; ++i) { + folly::once_flag flag; + int out = 0; + bm_impl([&] { folly::call_once(flag, [&] { ++out; }); }, 100); + ASSERT_EQ(1, out); + } +} diff --git a/folly/test/CallOnceBenchmark.cpp b/folly/test/CallOnceBenchmark.cpp deleted file mode 100644 index 5aca0c1a..00000000 --- a/folly/test/CallOnceBenchmark.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2017 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include - -#include - -#include - -DEFINE_int32(threads, 16, "benchmark concurrency"); - -template -void bm_impl(CallOnceFunc&& fn, int64_t iters) { - std::deque threads; - for (int i = 0; i < FLAGS_threads; ++i) { - threads.emplace_back([&fn, iters] { - for (int64_t j = 0; j < iters; ++j) { - fn(); - } - }); - } - for (std::thread& t : threads) { - t.join(); - } -} - -BENCHMARK(StdCallOnceBench, iters) { - std::once_flag flag; - int out = 0; - bm_impl([&] { std::call_once(flag, [&] { ++out; }); }, iters); - CHECK_EQ(1, out); -} - -BENCHMARK(FollyCallOnceBench, iters) { - folly::once_flag flag; - int out = 0; - bm_impl([&] { folly::call_once(flag, [&] { ++out; }); }, iters); - CHECK_EQ(1, out); -} - -int main(int argc, char** argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - folly::runBenchmarks(); - return 0; -} diff --git a/folly/test/CallOnceTest.cpp b/folly/test/CallOnceTest.cpp deleted file mode 100644 index e0dccd81..00000000 --- a/folly/test/CallOnceTest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017 Facebook, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include -#include -#include - -#include - -DEFINE_int32(threads, 16, "benchmark concurrency"); - -template -void bm_impl(CallOnceFunc&& fn, int64_t iters) { - std::deque threads; - for (int i = 0; i < FLAGS_threads; ++i) { - threads.emplace_back([&fn, iters] { - for (int64_t j = 0; j < iters; ++j) { - fn(); - } - }); - } - for (std::thread& t : threads) { - t.join(); - } -} - -TEST(FollyCallOnce, Simple) { - folly::once_flag flag; - auto fn = [&](int* outp) { ++*outp; }; - int out = 0; - folly::call_once(flag, fn, &out); - folly::call_once(flag, fn, &out); - ASSERT_EQ(1, out); -} - -TEST(FollyCallOnce, Exception) { - struct ExpectedException {}; - folly::once_flag flag; - size_t numCalls = 0; - EXPECT_THROW( - folly::call_once( - flag, - [&] { - ++numCalls; - throw ExpectedException(); - }), - ExpectedException); - EXPECT_EQ(1, numCalls); - folly::call_once(flag, [&] { ++numCalls; }); - EXPECT_EQ(2, numCalls); -} - -TEST(FollyCallOnce, Stress) { - for (int i = 0; i < 100; ++i) { - folly::once_flag flag; - int out = 0; - bm_impl([&] { folly::call_once(flag, [&] { ++out; }); }, 100); - ASSERT_EQ(1, out); - } -}