55152751567bcc7d00a7849aabc1f8afb943ea2a
[folly.git] / folly / test / SingletonTest.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <thread>
18
19 #include <folly/Singleton.h>
20 #include <folly/io/async/EventBase.h>
21 #include <folly/test/SingletonTestStructs.h>
22 #include <folly/Benchmark.h>
23
24 #include <glog/logging.h>
25 #include <gtest/gtest.h>
26 #include <boost/thread/barrier.hpp>
27
28 using namespace folly;
29
30 TEST(Singleton, MissingSingleton) {
31   EXPECT_DEATH([]() { auto u = Singleton<UnregisteredWatchdog>::try_get(); }(),
32       "");
33 }
34
35 struct BasicUsageTag {};
36 template <typename T, typename Tag = detail::DefaultTag>
37 using SingletonBasicUsage = Singleton <T, Tag, BasicUsageTag>;
38
39 // Exercise some basic codepaths ensuring registration order and
40 // destruction order happen as expected, that instances are created
41 // when expected, etc etc.
42 TEST(Singleton, BasicUsage) {
43   auto& vault = *SingletonVault::singleton<BasicUsageTag>();
44
45   EXPECT_EQ(vault.registeredSingletonCount(), 0);
46   SingletonBasicUsage<Watchdog> watchdog_singleton;
47   EXPECT_EQ(vault.registeredSingletonCount(), 1);
48
49   SingletonBasicUsage<ChildWatchdog> child_watchdog_singleton;
50   EXPECT_EQ(vault.registeredSingletonCount(), 2);
51
52   vault.registrationComplete();
53
54   // limit a scope to release references so we can destroy them later
55   {
56     std::shared_ptr<Watchdog> s1 = SingletonBasicUsage<Watchdog>::try_get();
57     EXPECT_NE(s1, nullptr);
58
59     std::shared_ptr<Watchdog> s2 = SingletonBasicUsage<Watchdog>::try_get();
60     EXPECT_NE(s2, nullptr);
61
62     EXPECT_EQ(s1, s2);
63
64     std::shared_ptr<ChildWatchdog> s3 =
65       SingletonBasicUsage<ChildWatchdog>::try_get();
66     EXPECT_NE(s3, nullptr);
67     EXPECT_NE(s2, s3);
68
69     EXPECT_EQ(vault.registeredSingletonCount(), 2);
70     EXPECT_EQ(vault.livingSingletonCount(), 2);
71   }
72
73   vault.destroyInstances();
74   EXPECT_EQ(vault.registeredSingletonCount(), 2);
75   EXPECT_EQ(vault.livingSingletonCount(), 0);
76 }
77
78 struct DirectUsageTag {};
79 template <typename T, typename Tag = detail::DefaultTag>
80 using SingletonDirectUsage = Singleton <T, Tag, DirectUsageTag>;
81
82 TEST(Singleton, DirectUsage) {
83   auto& vault = *SingletonVault::singleton<DirectUsageTag>();
84
85   EXPECT_EQ(vault.registeredSingletonCount(), 0);
86
87   // Verify we can get to the underlying singletons via directly using
88   // the singleton definition.
89   SingletonDirectUsage<Watchdog> watchdog;
90   struct TestTag {};
91   SingletonDirectUsage<Watchdog, TestTag> named_watchdog;
92   EXPECT_EQ(vault.registeredSingletonCount(), 2);
93   vault.registrationComplete();
94
95   EXPECT_NE(watchdog.try_get(), nullptr);
96   EXPECT_EQ(watchdog.try_get(), SingletonDirectUsage<Watchdog>::try_get());
97   EXPECT_NE(watchdog.try_get(), named_watchdog.try_get());
98   EXPECT_EQ(watchdog.try_get()->livingWatchdogCount(), 2);
99
100   vault.destroyInstances();
101 }
102
103 struct NamedUsageTag {};
104 template <typename T, typename Tag = detail::DefaultTag>
105 using SingletonNamedUsage = Singleton <T, Tag, NamedUsageTag>;
106
107 TEST(Singleton, NamedUsage) {
108   auto& vault = *SingletonVault::singleton<NamedUsageTag>();
109
110   EXPECT_EQ(vault.registeredSingletonCount(), 0);
111
112   // Define two named Watchdog singletons and one unnamed singleton.
113   struct Watchdog1 {};
114   struct Watchdog2 {};
115   typedef detail::DefaultTag Watchdog3;
116   SingletonNamedUsage<Watchdog, Watchdog1> watchdog1_singleton;
117   EXPECT_EQ(vault.registeredSingletonCount(), 1);
118   SingletonNamedUsage<Watchdog, Watchdog2> watchdog2_singleton;
119   EXPECT_EQ(vault.registeredSingletonCount(), 2);
120   SingletonNamedUsage<Watchdog, Watchdog3> watchdog3_singleton;
121   EXPECT_EQ(vault.registeredSingletonCount(), 3);
122
123   vault.registrationComplete();
124   {
125     // Verify our three singletons are distinct and non-nullptr.
126     auto s1 = SingletonNamedUsage<Watchdog, Watchdog1>::try_get();
127     EXPECT_EQ(s1, watchdog1_singleton.try_get());
128     auto s2 = SingletonNamedUsage<Watchdog, Watchdog2>::try_get();
129     EXPECT_EQ(s2, watchdog2_singleton.try_get());
130     EXPECT_NE(s1, s2);
131     auto s3 = SingletonNamedUsage<Watchdog, Watchdog3>::try_get();
132     EXPECT_EQ(s3, watchdog3_singleton.try_get());
133     EXPECT_NE(s3, s1);
134     EXPECT_NE(s3, s2);
135
136     // Verify the "default" singleton is the same as the DefaultTag-tagged
137     // singleton.
138     auto s4 = SingletonNamedUsage<Watchdog>::try_get();
139     EXPECT_EQ(s4, watchdog3_singleton.try_get());
140   }
141
142   vault.destroyInstances();
143 }
144
145 struct NaughtyUsageTag {};
146 template <typename T, typename Tag = detail::DefaultTag>
147 using SingletonNaughtyUsage = Singleton <T, Tag, NaughtyUsageTag>;
148 struct NaughtyUsageTag2 {};
149 template <typename T, typename Tag = detail::DefaultTag>
150 using SingletonNaughtyUsage2 = Singleton <T, Tag, NaughtyUsageTag2>;
151
152 // Some pathological cases such as getting unregistered singletons,
153 // double registration, etc.
154 TEST(Singleton, NaughtyUsage) {
155   auto& vault = *SingletonVault::singleton<NaughtyUsageTag>();
156
157   vault.registrationComplete();
158
159   // Unregistered.
160   EXPECT_DEATH(Singleton<Watchdog>::try_get(), "");
161   EXPECT_DEATH(SingletonNaughtyUsage<Watchdog>::try_get(), "");
162
163   vault.destroyInstances();
164
165   auto& vault2 = *SingletonVault::singleton<NaughtyUsageTag2>();
166
167    EXPECT_DEATH(SingletonNaughtyUsage2<Watchdog>::try_get(), "");
168   SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
169
170   // double registration
171   EXPECT_DEATH([]() { SingletonNaughtyUsage2<Watchdog> watchdog_singleton; }(),
172                "");
173   vault2.destroyInstances();
174
175   // double registration after destroy
176   EXPECT_DEATH([]() { SingletonNaughtyUsage2<Watchdog> watchdog_singleton; }(),
177                "");
178 }
179
180 struct SharedPtrUsageTag {};
181 template <typename T, typename Tag = detail::DefaultTag>
182 using SingletonSharedPtrUsage = Singleton <T, Tag, SharedPtrUsageTag>;
183
184 // TODO (anob): revisit this test
185 TEST(Singleton, SharedPtrUsage) {
186   struct WatchdogHolder {
187     ~WatchdogHolder() {
188       if (watchdog) {
189         LOG(ERROR) << "The following log message with stack trace is expected";
190       }
191     }
192
193     std::shared_ptr<Watchdog> watchdog;
194   };
195
196   auto& vault = *SingletonVault::singleton<SharedPtrUsageTag>();
197
198   EXPECT_EQ(vault.registeredSingletonCount(), 0);
199   SingletonSharedPtrUsage<Watchdog> watchdog_singleton;
200   EXPECT_EQ(vault.registeredSingletonCount(), 1);
201
202   SingletonSharedPtrUsage<ChildWatchdog> child_watchdog_singleton;
203   EXPECT_EQ(vault.registeredSingletonCount(), 2);
204
205   struct ATag {};
206   SingletonSharedPtrUsage<Watchdog, ATag> named_watchdog_singleton;
207
208   SingletonSharedPtrUsage<WatchdogHolder> watchdog_holder_singleton;
209
210   vault.registrationComplete();
211
212   // Initilize holder singleton first, so that it's the last one to be
213   // destroyed.
214   watchdog_holder_singleton.try_get();
215
216   auto s1 = SingletonSharedPtrUsage<Watchdog>::try_get().get();
217   EXPECT_NE(s1, nullptr);
218
219   auto s2 = SingletonSharedPtrUsage<Watchdog>::try_get().get();
220   EXPECT_NE(s2, nullptr);
221
222   EXPECT_EQ(s1, s2);
223
224   auto weak_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
225
226   auto shared_s1 = weak_s1.lock();
227   EXPECT_EQ(shared_s1.get(), s1);
228   EXPECT_EQ(shared_s1.use_count(), 2);
229
230   auto old_serial = shared_s1->serial_number;
231
232   {
233     auto named_weak_s1 =
234       SingletonSharedPtrUsage<Watchdog, ATag>::get_weak();
235     auto locked = named_weak_s1.lock();
236     EXPECT_NE(locked.get(), shared_s1.get());
237   }
238
239   // We should release externally locked shared_ptr, otherwise it will be
240   // considered a leak
241   watchdog_holder_singleton.try_get()->watchdog = std::move(shared_s1);
242
243   LOG(ERROR) << "The following log message regarding shared_ptr is expected";
244   {
245     auto start_time = std::chrono::steady_clock::now();
246     vault.destroyInstances();
247     auto duration = std::chrono::steady_clock::now() - start_time;
248     EXPECT_TRUE(duration > std::chrono::seconds{4} &&
249                 duration < std::chrono::seconds{6});
250   }
251   EXPECT_EQ(vault.registeredSingletonCount(), 4);
252   EXPECT_EQ(vault.livingSingletonCount(), 0);
253
254   EXPECT_TRUE(weak_s1.expired());
255
256   auto empty_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
257   EXPECT_FALSE(empty_s1.lock());
258
259   vault.reenableInstances();
260
261   {
262     // Singleton should be re-created only after reenableInstances() was called.
263     auto new_s1 = SingletonSharedPtrUsage<Watchdog>::try_get();
264     // Track serial number rather than pointer since the memory could be
265     // re-used when we create new_s1.
266     EXPECT_NE(new_s1->serial_number, old_serial);
267   }
268
269   auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
270   auto new_s1_shared = new_s1_weak.lock();
271   std::thread t([new_s1_shared]() mutable {
272       std::this_thread::sleep_for(std::chrono::seconds{2});
273       new_s1_shared.reset();
274     });
275   new_s1_shared.reset();
276   {
277     auto start_time = std::chrono::steady_clock::now();
278     vault.destroyInstances();
279     auto duration = std::chrono::steady_clock::now() - start_time;
280     EXPECT_TRUE(duration > std::chrono::seconds{1} &&
281                 duration < std::chrono::seconds{3});
282   }
283   EXPECT_TRUE(new_s1_weak.expired());
284   t.join();
285 }
286
287 // Some classes to test singleton dependencies.  NeedySingleton has a
288 // dependency on NeededSingleton, which happens during its
289 // construction.
290 struct NeedyTag {};
291 template <typename T, typename Tag = detail::DefaultTag>
292 using SingletonNeedy = Singleton <T, Tag, NeedyTag>;
293
294 struct NeededSingleton {};
295 struct NeedySingleton {
296   NeedySingleton() {
297     auto unused = SingletonNeedy<NeededSingleton>::try_get();
298     EXPECT_NE(unused, nullptr);
299   }
300 };
301
302 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
303 struct SelfNeedyTag {};
304 template <typename T, typename Tag = detail::DefaultTag>
305 using SingletonSelfNeedy = Singleton <T, Tag, SelfNeedyTag>;
306
307 struct SelfNeedySingleton {
308   SelfNeedySingleton() {
309     auto unused = SingletonSelfNeedy<SelfNeedySingleton>::try_get();
310     EXPECT_NE(unused, nullptr);
311   }
312 };
313
314 TEST(Singleton, SingletonDependencies) {
315   SingletonNeedy<NeededSingleton> needed_singleton;
316   SingletonNeedy<NeedySingleton> needy_singleton;
317   auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
318
319   needy_vault.registrationComplete();
320
321   EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
322   EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
323
324   auto needy = SingletonNeedy<NeedySingleton>::try_get();
325   EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
326
327   SingletonSelfNeedy<SelfNeedySingleton> self_needy_singleton;
328   auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
329
330   self_needy_vault.registrationComplete();
331   EXPECT_DEATH([]() { SingletonSelfNeedy<SelfNeedySingleton>::try_get(); }(),
332       "");
333 }
334
335 // A test to ensure multiple threads contending on singleton creation
336 // properly wait for creation rather than thinking it is a circular
337 // dependency.
338 class Slowpoke : public Watchdog {
339  public:
340   Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
341 };
342
343 struct ConcurrencyTag {};
344 template <typename T, typename Tag = detail::DefaultTag>
345 using SingletonConcurrency = Singleton <T, Tag, ConcurrencyTag>;
346
347 TEST(Singleton, SingletonConcurrency) {
348   auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
349   SingletonConcurrency<Slowpoke> slowpoke_singleton;
350   vault.registrationComplete();
351
352   std::mutex gatekeeper;
353   gatekeeper.lock();
354   auto func = [&gatekeeper]() {
355     gatekeeper.lock();
356     gatekeeper.unlock();
357     auto unused = SingletonConcurrency<Slowpoke>::try_get();
358   };
359
360   EXPECT_EQ(vault.livingSingletonCount(), 0);
361   std::vector<std::thread> threads;
362   for (int i = 0; i < 100; ++i) {
363     threads.emplace_back(func);
364   }
365   // If circular dependency checks fail, the unlock would trigger a
366   // crash.  Instead, it succeeds, and we have exactly one living
367   // singleton.
368   gatekeeper.unlock();
369   for (auto& t : threads) {
370     t.join();
371   }
372   EXPECT_EQ(vault.livingSingletonCount(), 1);
373 }
374
375 struct ErrorConstructor {
376   static size_t constructCount_;
377   ErrorConstructor() {
378     if ((constructCount_++) == 0) {
379       throw std::runtime_error("first time fails");
380     }
381   }
382 };
383 size_t ErrorConstructor::constructCount_(0);
384
385 struct CreationErrorTag {};
386 template <typename T, typename Tag = detail::DefaultTag>
387 using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>;
388
389 TEST(Singleton, SingletonCreationError) {
390   auto& vault = *SingletonVault::singleton<CreationErrorTag>();
391   SingletonCreationError<ErrorConstructor> error_once_singleton;
392
393   // first time should error out
394   EXPECT_THROW(error_once_singleton.get_weak().lock(), std::runtime_error);
395
396   // second time it'll work fine
397   error_once_singleton.get_weak().lock();
398   SUCCEED();
399 }
400
401 struct ConcurrencyStressTag {};
402 template <typename T, typename Tag = detail::DefaultTag>
403 using SingletonConcurrencyStress = Singleton <T, Tag, ConcurrencyStressTag>;
404
405 TEST(Singleton, SingletonConcurrencyStress) {
406   auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
407   SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
408
409   std::vector<std::thread> ts;
410   for (size_t i = 0; i < 100; ++i) {
411     ts.emplace_back([&]() {
412         slowpoke_singleton.get_weak().lock();
413       });
414   }
415
416   for (size_t i = 0; i < 100; ++i) {
417     std::chrono::milliseconds d(20);
418
419     std::this_thread::sleep_for(d);
420     vault.destroyInstances();
421     std::this_thread::sleep_for(d);
422     vault.destroyInstances();
423   }
424
425   for (auto& t : ts) {
426     t.join();
427   }
428 }
429
430 namespace {
431 struct EagerInitSyncTag {};
432 }
433 template <typename T, typename Tag = detail::DefaultTag>
434 using SingletonEagerInitSync = Singleton<T, Tag, EagerInitSyncTag>;
435 TEST(Singleton, SingletonEagerInitSync) {
436   auto& vault = *SingletonVault::singleton<EagerInitSyncTag>();
437   bool didEagerInit = false;
438   auto sing = SingletonEagerInitSync<std::string>(
439                   [&] {didEagerInit = true; return new std::string("foo"); })
440               .shouldEagerInit();
441   vault.registrationComplete();
442   EXPECT_FALSE(didEagerInit);
443   vault.doEagerInit();
444   EXPECT_TRUE(didEagerInit);
445   sing.get_weak();  // (avoid compile error complaining about unused var 'sing')
446 }
447
448 namespace {
449 struct EagerInitAsyncTag {};
450 }
451 template <typename T, typename Tag = detail::DefaultTag>
452 using SingletonEagerInitAsync = Singleton<T, Tag, EagerInitAsyncTag>;
453 TEST(Singleton, SingletonEagerInitAsync) {
454   auto& vault = *SingletonVault::singleton<EagerInitAsyncTag>();
455   bool didEagerInit = false;
456   auto sing = SingletonEagerInitAsync<std::string>(
457                   [&] {didEagerInit = true; return new std::string("foo"); })
458               .shouldEagerInit();
459   folly::EventBase eb;
460   vault.registrationComplete();
461   EXPECT_FALSE(didEagerInit);
462   auto result = vault.doEagerInitVia(&eb); // a Future<Unit> is returned
463   eb.loop();
464   result.get(); // ensure this completed successfully and didn't hang forever
465   EXPECT_TRUE(didEagerInit);
466   sing.get_weak();  // (avoid compile error complaining about unused var 'sing')
467 }
468
469 namespace {
470 class TestEagerInitParallelExecutor : public folly::Executor {
471  public:
472   explicit TestEagerInitParallelExecutor(const size_t threadCount) {
473     eventBases_.reserve(threadCount);
474     threads_.reserve(threadCount);
475     for (size_t i = 0; i < threadCount; i++) {
476       eventBases_.push_back(std::make_shared<folly::EventBase>());
477       auto eb = eventBases_.back();
478       threads_.emplace_back(std::make_shared<std::thread>(
479           [eb] { eb->loopForever(); }));
480     }
481   }
482
483   virtual ~TestEagerInitParallelExecutor() override {
484     for (auto eb : eventBases_) {
485       eb->runInEventBaseThread([eb] { eb->terminateLoopSoon(); });
486     }
487     for (auto thread : threads_) {
488       thread->join();
489     }
490   }
491
492   virtual void add(folly::Func func) override {
493     const auto index = (counter_ ++) % eventBases_.size();
494     eventBases_[index]->add(func);
495   }
496
497  private:
498   std::vector<std::shared_ptr<folly::EventBase>> eventBases_;
499   std::vector<std::shared_ptr<std::thread>> threads_;
500   std::atomic<size_t> counter_ {0};
501 };
502 }  // namespace
503
504 namespace {
505 struct EagerInitParallelTag {};
506 }
507 template <typename T, typename Tag = detail::DefaultTag>
508 using SingletonEagerInitParallel = Singleton<T, Tag, EagerInitParallelTag>;
509 TEST(Singleton, SingletonEagerInitParallel) {
510   const static size_t kIters = 1000;
511   const static size_t kThreads = 20;
512
513   std::atomic<size_t> initCounter;
514
515   auto& vault = *SingletonVault::singleton<EagerInitParallelTag>();
516
517   auto sing = SingletonEagerInitParallel<std::string>(
518                   [&] {++initCounter; return new std::string(""); })
519               .shouldEagerInit();
520
521   for (size_t i = 0; i < kIters; i++) {
522     SCOPE_EXIT {
523       // clean up each time
524       vault.destroyInstances();
525       vault.reenableInstances();
526     };
527
528     initCounter.store(0);
529
530     {
531       std::vector<std::shared_ptr<std::thread>> threads;
532       boost::barrier barrier(kThreads);
533       TestEagerInitParallelExecutor exe(kThreads);
534       vault.registrationComplete();
535
536       EXPECT_EQ(0, initCounter.load());
537
538       for (size_t j = 0; j < kThreads; j++) {
539         threads.push_back(std::make_shared<std::thread>([&] {
540           barrier.wait();
541           vault.doEagerInitVia(&exe).get();
542         }));
543       }
544
545       for (auto thread : threads) {
546         thread->join();
547       }
548     }
549
550     EXPECT_EQ(1, initCounter.load());
551
552     sing.get_weak();  // (avoid compile error complaining about unused var)
553   }
554 }
555
556 // Benchmarking a normal singleton vs a Meyers singleton vs a Folly
557 // singleton.  Meyers are insanely fast, but (hopefully) Folly
558 // singletons are fast "enough."
559 int* getMeyersSingleton() {
560   static auto ret = new int(0);
561   return ret;
562 }
563
564 int normal_singleton_value = 0;
565 int* getNormalSingleton() {
566   doNotOptimizeAway(&normal_singleton_value);
567   return &normal_singleton_value;
568 }
569
570 struct MockTag {};
571 template <typename T, typename Tag = detail::DefaultTag>
572 using SingletonMock = Singleton <T, Tag, MockTag>;
573
574 // Verify that existing Singleton's can be overridden
575 // using the make_mock functionality.
576 TEST(Singleton, MockTest) {
577   auto& vault = *SingletonVault::singleton<MockTag>();
578
579   SingletonMock<Watchdog> watchdog_singleton;
580   vault.registrationComplete();
581
582   // Registring singletons after registrationComplete called works
583   // with make_mock (but not with Singleton ctor).
584   EXPECT_EQ(vault.registeredSingletonCount(), 1);
585   int serial_count_first = SingletonMock<Watchdog>::try_get()->serial_number;
586
587   // Override existing mock using make_mock.
588   SingletonMock<Watchdog>::make_mock();
589
590   EXPECT_EQ(vault.registeredSingletonCount(), 1);
591   int serial_count_mock = SingletonMock<Watchdog>::try_get()->serial_number;
592
593   // If serial_count value is the same, then singleton was not replaced.
594   EXPECT_NE(serial_count_first, serial_count_mock);
595 }
596
597 struct BenchmarkSingleton {
598   int val = 0;
599 };
600
601 BENCHMARK(NormalSingleton, n) {
602   for (size_t i = 0; i < n; ++i) {
603     doNotOptimizeAway(getNormalSingleton());
604   }
605 }
606
607 BENCHMARK_RELATIVE(MeyersSingleton, n) {
608   for (size_t i = 0; i < n; ++i) {
609     doNotOptimizeAway(getMeyersSingleton());
610   }
611 }
612
613 struct BenchmarkTag {};
614 template <typename T, typename Tag = detail::DefaultTag>
615 using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
616
617 struct GetTag{};
618 struct GetWeakTag{};
619
620 SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
621 SingletonBenchmark<BenchmarkSingleton, GetWeakTag> benchmark_singleton_get_weak;
622
623 BENCHMARK_RELATIVE(FollySingleton, n) {
624   for (size_t i = 0; i < n; ++i) {
625     SingletonBenchmark<BenchmarkSingleton, GetTag>::try_get();
626   }
627 }
628
629 BENCHMARK_RELATIVE(FollySingletonWeak, n) {
630   for (size_t i = 0; i < n; ++i) {
631     SingletonBenchmark<BenchmarkSingleton, GetWeakTag>::get_weak();
632   }
633 }
634
635 int main(int argc, char* argv[]) {
636   testing::InitGoogleTest(&argc, argv);
637   google::InitGoogleLogging(argv[0]);
638   gflags::ParseCommandLineFlags(&argc, &argv, true);
639
640   SingletonVault::singleton()->registrationComplete();
641
642   auto ret = RUN_ALL_TESTS();
643   if (!ret) {
644     folly::runBenchmarksOnFlag();
645   }
646   return ret;
647 }