From b3ab0cc4e44eedfd83699a58befce5daebb7d228 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Tue, 27 Jun 2017 12:09:05 -0700 Subject: [PATCH] Move folly/experimental/AtomicSharedPtr.h -> folly/concurrency/AtomicSharedPtr.h Summary: As title. Reviewed By: WillerZ, yfeldblum, ivmaykov Differential Revision: D5312308 fbshipit-source-id: 91ad4bb39df0619f2885e13c1fda1e018292a40e --- folly/Makefile.am | 4 +- .../AtomicSharedPtr.h | 2 +- .../detail/AtomicSharedPtr-detail.h | 0 .../test/AtomicSharedPtrCounted.h | 0 .../test/AtomicSharedPtrPerformance.cpp | 227 ++++++++++++++++++ .../test/AtomicSharedPtrTest.cpp | 4 +- 6 files changed, 232 insertions(+), 5 deletions(-) rename folly/{experimental => concurrency}/AtomicSharedPtr.h (99%) rename folly/{experimental => concurrency}/detail/AtomicSharedPtr-detail.h (100%) rename folly/{experimental => concurrency}/test/AtomicSharedPtrCounted.h (100%) create mode 100644 folly/concurrency/test/AtomicSharedPtrPerformance.cpp rename folly/{experimental => concurrency}/test/AtomicSharedPtrTest.cpp (97%) diff --git a/folly/Makefile.am b/folly/Makefile.am index a949b1ce..74977332 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -97,9 +97,9 @@ nobase_follyinclude_HEADERS = \ ExceptionWrapper-inl.h \ Executor.h \ Expected.h \ + concurrency/AtomicSharedPtr.h \ + concurrency/detail/AtomicSharedPtr-detail.h \ experimental/AsymmetricMemoryBarrier.h \ - experimental/AtomicSharedPtr.h \ - experimental/detail/AtomicSharedPtr-detail.h \ experimental/AutoTimer.h \ experimental/ThreadedRepeatingFunctionRunner.h \ experimental/Bits.h \ diff --git a/folly/experimental/AtomicSharedPtr.h b/folly/concurrency/AtomicSharedPtr.h similarity index 99% rename from folly/experimental/AtomicSharedPtr.h rename to folly/concurrency/AtomicSharedPtr.h index 7e8dce05..bd400d3c 100644 --- a/folly/experimental/AtomicSharedPtr.h +++ b/folly/concurrency/AtomicSharedPtr.h @@ -17,8 +17,8 @@ #include #include +#include #include -#include #include #include diff --git a/folly/experimental/detail/AtomicSharedPtr-detail.h b/folly/concurrency/detail/AtomicSharedPtr-detail.h similarity index 100% rename from folly/experimental/detail/AtomicSharedPtr-detail.h rename to folly/concurrency/detail/AtomicSharedPtr-detail.h diff --git a/folly/experimental/test/AtomicSharedPtrCounted.h b/folly/concurrency/test/AtomicSharedPtrCounted.h similarity index 100% rename from folly/experimental/test/AtomicSharedPtrCounted.h rename to folly/concurrency/test/AtomicSharedPtrCounted.h diff --git a/folly/concurrency/test/AtomicSharedPtrPerformance.cpp b/folly/concurrency/test/AtomicSharedPtrPerformance.cpp new file mode 100644 index 00000000..b2df2a1f --- /dev/null +++ b/folly/concurrency/test/AtomicSharedPtrPerformance.cpp @@ -0,0 +1,227 @@ +/* + * Copyright 2016-present 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 +#include +#include + +using std::shared_ptr; +using std::make_shared; +using std::cerr; +using std::cout; +using std::endl; +using std::condition_variable; +using std::unique_lock; +using std::mutex; +using std::vector; +using std::thread; +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_acquire; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_seq_cst; +using std::move; +using std::ref; +using std::is_same; +using std::atomic; +using std::chrono::steady_clock; +using std::chrono::duration_cast; +using std::chrono::microseconds; + +static uint64_t nowMicro() { + return duration_cast(steady_clock::now().time_since_epoch()) + .count(); +} + +static const char* memoryOrder(memory_order order) { + switch (order) { + case memory_order_relaxed: + return "relaxed"; + case memory_order_acquire: + return "acquire"; + case memory_order_release: + return "release"; + case memory_order_acq_rel: + return "acq_rel"; + case memory_order_seq_cst: + return "seq_cst"; + default: + return ""; + } +} + +template +void uncontended_read_write( + size_t readers, + size_t writers, + memory_order readOrder = memory_order_seq_cst, + memory_order writeOrder = memory_order_seq_cst) { + std::shared_ptr zero = std::make_shared(0); + T a(zero); + auto time1 = nowMicro(); + for (size_t i = 0; i < 10000000; ++i) { + for (size_t j = 0; j < readers; ++j) { + a.load(readOrder); + } + for (size_t j = 0; j < writers; ++j) { + a.store(zero, writeOrder); + } + } + auto time2 = nowMicro(); + cout << "Uncontended Read(" << readers << "," << memoryOrder(readOrder) + << ")/Write(" << writers << "," << memoryOrder(writeOrder) + << "): " << (time2 - time1) << " \u03BCs" << endl; +} + +template +void read_asp( + unique_lock lock, + condition_variable& cvar, + atomic& go, + T& aptr, + memory_order order) { + cvar.wait(lock, [&go]() { + return atomic_load_explicit(&go, memory_order_acquire); + }); + lock.unlock(); + for (size_t i = 0; i < 1000000; ++i) { + aptr.load(order); + } +} + +template +void write_asp( + unique_lock lock, + condition_variable& cvar, + atomic& go, + T& aptr, + memory_order order) { + std::shared_ptr zero = std::make_shared(0); + cvar.wait(lock, [&go]() { + return atomic_load_explicit(&go, memory_order_acquire); + }); + lock.unlock(); + for (size_t i = 0; i < 1000000; ++i) { + aptr.store(zero, order); + } +} + +template +void contended_read_write( + size_t readers, + size_t writers, + memory_order readOrder = memory_order_seq_cst, + memory_order writeOrder = memory_order_seq_cst) { + vector threads; + mutex lock; + condition_variable cvar; + atomic go{false}; + T aptr(std::make_shared()); + for (size_t i = 0; i < readers; ++i) { + unique_lock ulock(lock); + threads.emplace_back( + &read_asp, move(ulock), ref(cvar), ref(go), ref(aptr), readOrder); + } + for (size_t i = 0; i < writers; ++i) { + unique_lock ulock(lock); + threads.emplace_back( + &write_asp, move(ulock), ref(cvar), ref(go), ref(aptr), writeOrder); + } + unique_lock ulock(lock); + ulock.unlock(); + atomic_store_explicit(&go, true, memory_order_release); + auto time1 = nowMicro(); + cvar.notify_all(); + for (auto& thread : threads) { + thread.join(); + } + auto time2 = nowMicro(); + cout << "Contended Read(" << readers << "," << memoryOrder(readOrder) + << ")/Write(" << writers << "," << memoryOrder(writeOrder) + << "): " << (time2 - time1) << " \u03BCs" << endl; +} + +template +void document_noexcept() { + shared_ptr ptr = make_shared(0); + T aptr{}; + cout << " ctor () is " << (noexcept(T()) ? "" : "not ") << "noexcept." + << endl; + cout << " ctor (ptr) is " << (noexcept(T(ptr)) ? "" : "not ") << "noexcept." + << endl; +#define _(A) \ + do { \ + cout << " " #A " is " << (noexcept(aptr.A) ? "" : "not ") << "noexcept." \ + << endl; \ + } while (0) + _(operator=(ptr)); + + _(is_lock_free()); + + _(store(ptr)); + _(store(ptr, memory_order_seq_cst)); + + _(load()); + _(load(memory_order_seq_cst)); + + _(exchange(ptr)); + _(exchange(ptr, memory_order_seq_cst)); + + _(compare_exchange_strong(ptr, ptr)); + _(compare_exchange_strong(ptr, ptr, memory_order_seq_cst)); + _(compare_exchange_strong( + ptr, ptr, memory_order_seq_cst, memory_order_seq_cst)); + + _(compare_exchange_weak(ptr, ptr)); + _(compare_exchange_weak(ptr, ptr, memory_order_seq_cst)); + _(compare_exchange_weak( + ptr, ptr, memory_order_seq_cst, memory_order_seq_cst)); + +#undef _ + cout << " operator std::shared_ptr() is " + << (noexcept(ptr = aptr) ? "" : "not ") << "noexcept." << endl; +} + +template +void runSuite() { + document_noexcept(); + uncontended_read_write(10, 0); + uncontended_read_write(0, 10); + uncontended_read_write(10, 10); + uncontended_read_write(10, 10, memory_order_relaxed, memory_order_relaxed); + uncontended_read_write(10, 10, memory_order_acquire, memory_order_release); + contended_read_write(10, 0); + contended_read_write(0, 10); + contended_read_write(1, 1); + contended_read_write(5, 1); + contended_read_write(10, 1); + contended_read_write(100, 1); + contended_read_write(100, 1, memory_order_relaxed, memory_order_relaxed); + contended_read_write(100, 1, memory_order_acquire, memory_order_release); +} + +int main(int, char**) { + cout << endl << "Folly implementation. Is lock free: 1" << endl; + runSuite>(); + return 0; +} diff --git a/folly/experimental/test/AtomicSharedPtrTest.cpp b/folly/concurrency/test/AtomicSharedPtrTest.cpp similarity index 97% rename from folly/experimental/test/AtomicSharedPtrTest.cpp rename to folly/concurrency/test/AtomicSharedPtrTest.cpp index 06b42d8a..aa8c5434 100644 --- a/folly/experimental/test/AtomicSharedPtrTest.cpp +++ b/folly/concurrency/test/AtomicSharedPtrTest.cpp @@ -17,8 +17,8 @@ #include #include -#include -#include +#include +#include #include #include -- 2.34.1