return instance_weak_.lock();
}
+template <typename T>
+folly::ReadMostlySharedPtr<T> SingletonHolder<T>::try_get_fast() {
+ if (UNLIKELY(state_.load(std::memory_order_acquire) !=
+ SingletonHolderState::Living)) {
+ createInstance();
+ }
+
+ return instance_weak_fast_.lock();
+}
+
template <typename T>
TypeDescriptor SingletonHolder<T>::type() {
return type_;
auto type_name = type_.name();
// Can't use make_shared -- no support for a custom deleter, sadly.
- instance_ = std::shared_ptr<T>(
+ std::shared_ptr<T> instance(
create_(),
[destroy_baton, print_destructor_stack_trace, teardown, type_name]
(T* instance_ptr) mutable {
// constructor
SingletonVault::scheduleDestroyInstances();
- instance_weak_ = instance_;
- instance_ptr_ = instance_.get();
+ instance_weak_ = instance;
+ instance_ptr_ = instance.get();
+ instance_.reset(std::move(instance));
+ instance_weak_fast_ = instance_;
+
destroy_baton_ = std::move(destroy_baton);
print_destructor_stack_trace_ = std::move(print_destructor_stack_trace);
#include <folly/Demangle.h>
#include <folly/Executor.h>
#include <folly/io/async/Request.h>
+#include <folly/experimental/ReadMostlySharedPtr.h>
#include <algorithm>
#include <atomic>
inline T* get();
inline std::weak_ptr<T> get_weak();
inline std::shared_ptr<T> try_get();
+ inline folly::ReadMostlySharedPtr<T> try_get_fast();
void registerSingleton(CreateFunc c, TeardownFunc t);
void registerSingletonMock(CreateFunc c, TeardownFunc t);
// The singleton itself and related functions.
- // holds a shared_ptr to singleton instance, set when state is changed from
- // Dead to Living. Reset when state is changed from Living to Dead.
- std::shared_ptr<T> instance_;
+ // holds a ReadMostlyMainPtr to singleton instance, set when state is changed
+ // from Dead to Living. Reset when state is changed from Living to Dead.
+ folly::ReadMostlyMainPtr<T> instance_;
// weak_ptr to the singleton instance, set when state is changed from Dead
// to Living. We never write to this object after initialization, so it is
// safe to read it from different threads w/o synchronization if we know
// that state is set to Living
std::weak_ptr<T> instance_weak_;
+ // Fast equivalent of instance_weak_
+ folly::ReadMostlyWeakPtr<T> instance_weak_fast_;
// Time we wait on destroy_baton after releasing Singleton shared_ptr.
std::shared_ptr<folly::Baton<>> destroy_baton_;
T* instance_ptr_ = nullptr;
return getEntry().try_get();
}
+ static folly::ReadMostlySharedPtr<T> try_get_fast() {
+ return getEntry().try_get_fast();
+ }
+
explicit Singleton(std::nullptr_t _ = nullptr,
typename Singleton::TeardownFunc t = nullptr) :
Singleton ([]() { return new T; }, std::move(t)) {
#include <atomic>
-#include <folly/experimental/RCURefCount.h>
#include <folly/experimental/TLRefCount.h>
namespace folly {
void increfWeak() {
auto value = ++weakCount_;
- assert(value > 0);
+ DCHECK_GT(value, 0);
}
void decrefWeak() {
reset(mainPtr.impl_);
}
+ explicit ReadMostlyWeakPtr(const ReadMostlySharedPtr<T, RefCount>& ptr) {
+ reset(ptr.impl_);
+ }
+
ReadMostlyWeakPtr(const ReadMostlyWeakPtr& other) {
*this = other;
}
return *this;
}
+ ReadMostlyWeakPtr& operator=(const ReadMostlyMainPtr<T, RefCount>& mainPtr) {
+ reset(mainPtr.impl_);
+ return *this;
+ }
+
ReadMostlyWeakPtr(ReadMostlyWeakPtr&& other) noexcept {
*this = other;
}
}
private:
+ friend class ReadMostlyWeakPtr<T, RefCount>;
+
void reset(detail::ReadMostlySharedPtrCore<T, RefCount>* impl) {
if (impl_) {
impl_->decref();
#include <folly/Memory.h>
#include <gflags/gflags.h>
+#include <folly/experimental/RCURefCount.h>
#include <folly/experimental/ReadMostlySharedPtr.h>
template <template<typename> class MainPtr,
#include <gtest/gtest.h>
#include <folly/Baton.h>
+#include <folly/experimental/RCURefCount.h>
#include <folly/experimental/ReadMostlySharedPtr.h>
using folly::ReadMostlyMainPtr;
--- /dev/null
+/*
+ * Copyright 2015 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.
+ */
+/* -*- Mode: C++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+#include <thread>
+#include <iostream>
+#include <folly/Benchmark.h>
+#include <folly/Memory.h>
+#include <gflags/gflags.h>
+
+#include <folly/Singleton.h>
+
+using namespace folly;
+
+// Benchmarking a normal singleton vs a Meyers singleton vs a Folly
+// singleton. Meyers are insanely fast, but (hopefully) Folly
+// singletons are fast "enough."
+int* getMeyersSingleton() {
+ static auto ret = new int(0);
+ return ret;
+}
+
+int normal_singleton_value = 0;
+int* getNormalSingleton() {
+ doNotOptimizeAway(&normal_singleton_value);
+ return &normal_singleton_value;
+}
+
+struct BenchmarkSingleton {
+ int val = 0;
+};
+
+void run4Threads(std::function<void()> f) {
+ std::vector<std::thread> threads;
+ for (size_t i = 0; i < 4; ++ i) {
+ threads.emplace_back(f);
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+void normalSingleton(size_t n) {
+ for (size_t i = 0; i < n; ++ i) {
+ doNotOptimizeAway(getNormalSingleton());
+ }
+}
+
+BENCHMARK(NormalSingleton, n) {
+ normalSingleton(n);
+}
+
+BENCHMARK(NormalSingleton4Threads, n) {
+ run4Threads([=]() {
+ normalSingleton(n);
+ });
+}
+
+void meyersSingleton(size_t n) {
+ for (size_t i = 0; i < n; ++i) {
+ doNotOptimizeAway(getMeyersSingleton());
+ }
+}
+
+
+BENCHMARK(MeyersSingleton, n) {
+ meyersSingleton(n);
+}
+
+BENCHMARK(MeyersSingleton4Threads, n) {
+ run4Threads([=]() {
+ meyersSingleton(n);
+ });
+}
+
+struct BenchmarkTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
+
+struct GetTag{};
+struct TryGetTag{};
+struct TryGetFastTag{};
+
+SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
+SingletonBenchmark<BenchmarkSingleton, TryGetTag> benchmark_singleton_try_get;
+SingletonBenchmark<BenchmarkSingleton, TryGetFastTag>
+benchmark_singleton_try_get_fast;
+
+void follySingletonRaw(size_t n) {
+ for (size_t i = 0; i < n; ++i) {
+ SingletonBenchmark<BenchmarkSingleton, GetTag>::get();
+ }
+}
+
+BENCHMARK(FollySingletonRaw, n) {
+ follySingletonRaw(n);
+}
+
+BENCHMARK(FollySingletonRaw4Threads, n) {
+ run4Threads([=]() {
+ follySingletonRaw(n);
+ });
+}
+
+void follySingletonTryGet(size_t n) {
+ for (size_t i = 0; i < n; ++i) {
+ SingletonBenchmark<BenchmarkSingleton, TryGetTag>::try_get();
+ }
+}
+
+BENCHMARK(FollySingletonTryGet, n) {
+ follySingletonTryGet(n);
+}
+
+BENCHMARK(FollySingletonTryGet4Threads, n) {
+ run4Threads([=]() {
+ follySingletonTryGet(n);
+ });
+}
+
+void follySingletonTryGetFast(size_t n) {
+ for (size_t i = 0; i < n; ++i) {
+ SingletonBenchmark<BenchmarkSingleton, TryGetFastTag>::try_get_fast();
+ }
+}
+
+BENCHMARK(FollySingletonTryGetFast, n) {
+ follySingletonTryGetFast(n);
+}
+
+BENCHMARK(FollySingletonTryGetFast4Threads, n) {
+ run4Threads([=]() {
+ follySingletonTryGetFast(n);
+ });
+}
+
+int main(int argc, char** argv) {
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
+ gflags::SetCommandLineOptionWithMode(
+ "bm_min_usec", "100000", gflags::SET_FLAG_IF_DEFAULT
+ );
+
+ folly::runBenchmarks();
+
+ return 0;
+}
#include <folly/Singleton.h>
#include <folly/io/async/EventBase.h>
#include <folly/test/SingletonTestStructs.h>
-#include <folly/Benchmark.h>
#include <glog/logging.h>
#include <gtest/gtest.h>
EXPECT_NE(s2, nullptr);
EXPECT_EQ(s1, s2);
+ EXPECT_EQ(s1.get(), SingletonBasicUsage<Watchdog>::try_get_fast().get());
std::shared_ptr<ChildWatchdog> s3 =
SingletonBasicUsage<ChildWatchdog>::try_get();
}
}
-// Benchmarking a normal singleton vs a Meyers singleton vs a Folly
-// singleton. Meyers are insanely fast, but (hopefully) Folly
-// singletons are fast "enough."
-int* getMeyersSingleton() {
- static auto ret = new int(0);
- return ret;
-}
-
-int normal_singleton_value = 0;
-int* getNormalSingleton() {
- doNotOptimizeAway(&normal_singleton_value);
- return &normal_singleton_value;
-}
-
struct MockTag {};
template <typename T, typename Tag = detail::DefaultTag>
using SingletonMock = Singleton <T, Tag, MockTag>;
EXPECT_NE(serial_count_first, serial_count_mock);
}
-struct BenchmarkSingleton {
- int val = 0;
-};
-
-void run4Threads(std::function<void()> f) {
- std::vector<std::thread> threads;
- for (size_t i = 0; i < 4; ++ i) {
- threads.emplace_back(f);
- }
- for (auto& thread : threads) {
- thread.join();
- }
-}
-
-void normalSingleton(size_t n) {
- for (size_t i = 0; i < n; ++ i) {
- doNotOptimizeAway(getNormalSingleton());
- }
-}
-
-BENCHMARK(NormalSingleton, n) {
- normalSingleton(n);
-}
-
-BENCHMARK(NormalSingleton4Threads, n) {
- run4Threads([=]() {
- normalSingleton(n);
- });
-}
-
-void meyersSingleton(size_t n) {
- for (size_t i = 0; i < n; ++i) {
- doNotOptimizeAway(getMeyersSingleton());
- }
-}
-
-
-BENCHMARK_RELATIVE(MeyersSingleton, n) {
- meyersSingleton(n);
-}
-
-BENCHMARK_RELATIVE(MeyersSingleton4Threads, n) {
- run4Threads([=]() {
- meyersSingleton(n);
- });
-}
-
-struct BenchmarkTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
-
-struct GetTag{};
-struct GetSharedTag{};
-struct GetWeakTag{};
-
-SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
-SingletonBenchmark<BenchmarkSingleton, GetSharedTag>
-benchmark_singleton_get_shared;
-SingletonBenchmark<BenchmarkSingleton, GetWeakTag> benchmark_singleton_get_weak;
-
-void follySingletonRaw(size_t n) {
- for (size_t i = 0; i < n; ++i) {
- SingletonBenchmark<BenchmarkSingleton, GetTag>::get();
- }
-}
-
-BENCHMARK_RELATIVE(FollySingletonRaw, n) {
- follySingletonRaw(n);
-}
-
-BENCHMARK_RELATIVE(FollySingletonRaw4Threads, n) {
- run4Threads([=]() {
- follySingletonRaw(n);
- });
-}
-
-void follySingletonSharedPtr(size_t n) {
- for (size_t i = 0; i < n; ++i) {
- SingletonBenchmark<BenchmarkSingleton, GetSharedTag>::try_get();
- }
-}
-
-BENCHMARK_RELATIVE(FollySingletonSharedPtr, n) {
- follySingletonSharedPtr(n);
-}
-
-BENCHMARK_RELATIVE(FollySingletonSharedPtr4Threads, n) {
- run4Threads([=]() {
- follySingletonSharedPtr(n);
- });
-}
-
-void follySingletonWeakPtr(size_t n) {
- for (size_t i = 0; i < n; ++i) {
- SingletonBenchmark<BenchmarkSingleton, GetWeakTag>::get_weak();
- }
-}
-
-BENCHMARK_RELATIVE(FollySingletonWeakPtr, n) {
- follySingletonWeakPtr(n);
-}
-
-BENCHMARK_RELATIVE(FollySingletonWeakPtr4Threads, n) {
- run4Threads([=]() {
- follySingletonWeakPtr(n);
- });
-}
-
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
google::InitGoogleLogging(argv[0]);
SingletonVault::singleton()->registrationComplete();
auto ret = RUN_ALL_TESTS();
- if (!ret) {
- folly::runBenchmarksOnFlag();
- }
+
return ret;
}