Improve folly::Singleton try_get perf and bring back raw get benchmark
authorAndrii Grynenko <andrii@fb.com>
Wed, 21 Oct 2015 02:34:57 +0000 (19:34 -0700)
committerfacebook-github-bot-4 <folly-bot@fb.com>
Wed, 21 Oct 2015 03:20:19 +0000 (20:20 -0700)
Reviewed By: elsteveogrande

Differential Revision: D2517522

fb-gh-sync-id: eab11d17ce5db94e09aa733b6067e44d36be6345

folly/Singleton-inl.h
folly/Singleton.h
folly/test/SingletonTest.cpp

index e946e8a51ba632b695f7c2af962100ad769a8770..deca4b2c9ddcc64346767ac139d67e689790f04d 100644 (file)
@@ -76,7 +76,8 @@ void SingletonHolder<T>::registerSingletonMock(CreateFunc c, TeardownFunc t) {
 
 template <typename T>
 T* SingletonHolder<T>::get() {
-  if (LIKELY(state_ == SingletonHolderState::Living)) {
+  if (LIKELY(state_.load(std::memory_order_acquire) ==
+             SingletonHolderState::Living)) {
     return instance_ptr_;
   }
   createInstance();
@@ -93,13 +94,24 @@ T* SingletonHolder<T>::get() {
 
 template <typename T>
 std::weak_ptr<T> SingletonHolder<T>::get_weak() {
-  if (UNLIKELY(state_ != SingletonHolderState::Living)) {
+  if (UNLIKELY(state_.load(std::memory_order_acquire) !=
+               SingletonHolderState::Living)) {
     createInstance();
   }
 
   return instance_weak_;
 }
 
+template <typename T>
+std::shared_ptr<T> SingletonHolder<T>::try_get() {
+  if (UNLIKELY(state_.load(std::memory_order_acquire) !=
+               SingletonHolderState::Living)) {
+    createInstance();
+  }
+
+  return instance_weak_.lock();
+}
+
 template <typename T>
 TypeDescriptor SingletonHolder<T>::type() {
   return type_;
index 01e0bed593e9f0b11d9f31aa27c9ec1f14c544c9..194eb6b462e7e0f6f83ed4577c86f24ae2ee37af 100644 (file)
@@ -243,6 +243,7 @@ struct SingletonHolder : public SingletonHolderBase {
 
   inline T* get();
   inline std::weak_ptr<T> get_weak();
+  inline std::shared_ptr<T> try_get();
 
   void registerSingleton(CreateFunc c, TeardownFunc t);
   void registerSingletonMock(CreateFunc c, TeardownFunc t);
@@ -494,7 +495,7 @@ class Singleton {
   // Avoid holding these shared_ptrs beyond the scope of a function;
   // don't put them in member variables, always use try_get() instead
   static std::shared_ptr<T> try_get() {
-    auto ret = get_weak().lock();
+    auto ret = getEntry().try_get();
     if (!ret) {
       LOG(DFATAL) <<
         "folly::Singleton<" << getEntry().type().name() <<
index da62e18fc6e05019f876931b200630f535bb2c40..575e136f5c445b4c8c93005d1a06bdab3d6b4ffe 100644 (file)
@@ -599,40 +599,110 @@ struct BenchmarkSingleton {
   int val = 0;
 };
 
-BENCHMARK(NormalSingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
+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_RELATIVE(MeyersSingleton, n) {
+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;
 
-BENCHMARK_RELATIVE(FollySingleton, n) {
+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, GetTag>::try_get();
+    SingletonBenchmark<BenchmarkSingleton, GetSharedTag>::try_get();
   }
 }
 
-BENCHMARK_RELATIVE(FollySingletonWeak, n) {
+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]);