get_fast/get_weak_fast API for folly::Singleton
[folly.git] / folly / experimental / test / SingletonTest.cpp
1 /*
2  * Copyright 2014 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/experimental/Singleton.h>
20
21 #include <folly/Benchmark.h>
22
23 #include <glog/logging.h>
24 #include <gtest/gtest.h>
25
26 using namespace folly;
27
28 // A simple class that tracks how often instances of the class and
29 // subclasses are created, and the ordering.  Also tracks a global
30 // unique counter for each object.
31 std::atomic<size_t> global_counter(19770326);
32 struct Watchdog {
33   static std::vector<Watchdog*> creation_order;
34   Watchdog() : serial_number(++global_counter) {
35     creation_order.push_back(this);
36   }
37
38   ~Watchdog() {
39     if (creation_order.back() != this) {
40       throw std::out_of_range("Watchdog destruction order mismatch");
41     }
42     creation_order.pop_back();
43   }
44
45   const size_t serial_number;
46   size_t livingWatchdogCount() const { return creation_order.size(); }
47
48   Watchdog(const Watchdog&) = delete;
49   Watchdog& operator=(const Watchdog&) = delete;
50   Watchdog(Watchdog&&) noexcept = default;
51 };
52
53 std::vector<Watchdog*> Watchdog::creation_order;
54
55 // Some basic types we use for tracking.
56 struct ChildWatchdog : public Watchdog {};
57 struct GlobalWatchdog : public Watchdog {};
58 struct UnregisteredWatchdog : public Watchdog {};
59
60 namespace {
61 Singleton<GlobalWatchdog> global_watchdog;
62 }
63
64 // Test basic global usage (the default way singletons will generally
65 // be used).
66 TEST(Singleton, BasicGlobalUsage) {
67   EXPECT_EQ(Watchdog::creation_order.size(), 0);
68   EXPECT_EQ(SingletonVault::singleton()->registeredSingletonCount(), 1);
69   EXPECT_EQ(SingletonVault::singleton()->livingSingletonCount(), 0);
70   auto wd1 = Singleton<GlobalWatchdog>::get();
71   EXPECT_NE(wd1, nullptr);
72   EXPECT_EQ(Watchdog::creation_order.size(), 1);
73   auto wd2 = Singleton<GlobalWatchdog>::get();
74   EXPECT_NE(wd2, nullptr);
75   EXPECT_EQ(wd1, wd2);
76   EXPECT_EQ(Watchdog::creation_order.size(), 1);
77   SingletonVault::singleton()->destroyInstances();
78   EXPECT_EQ(Watchdog::creation_order.size(), 0);
79 }
80
81 TEST(Singleton, MissingSingleton) {
82   EXPECT_THROW([]() { auto u = Singleton<UnregisteredWatchdog>::get(); }(),
83                std::out_of_range);
84 }
85
86 // Exercise some basic codepaths ensuring registration order and
87 // destruction order happen as expected, that instances are created
88 // when expected, etc etc.
89 TEST(Singleton, BasicUsage) {
90   SingletonVault vault;
91
92   EXPECT_EQ(vault.registeredSingletonCount(), 0);
93   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
94   EXPECT_EQ(vault.registeredSingletonCount(), 1);
95
96   Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
97   EXPECT_EQ(vault.registeredSingletonCount(), 2);
98
99   vault.registrationComplete();
100
101   Watchdog* s1 = Singleton<Watchdog>::get(&vault);
102   EXPECT_NE(s1, nullptr);
103
104   Watchdog* s2 = Singleton<Watchdog>::get(&vault);
105   EXPECT_NE(s2, nullptr);
106
107   EXPECT_EQ(s1, s2);
108
109   auto s3 = Singleton<ChildWatchdog>::get(&vault);
110   EXPECT_NE(s3, nullptr);
111   EXPECT_NE(s2, s3);
112
113   EXPECT_EQ(vault.registeredSingletonCount(), 2);
114   EXPECT_EQ(vault.livingSingletonCount(), 2);
115
116   vault.destroyInstances();
117   EXPECT_EQ(vault.registeredSingletonCount(), 2);
118   EXPECT_EQ(vault.livingSingletonCount(), 0);
119 }
120
121 TEST(Singleton, DirectUsage) {
122   SingletonVault vault;
123
124   EXPECT_EQ(vault.registeredSingletonCount(), 0);
125
126   // Verify we can get to the underlying singletons via directly using
127   // the singleton definition.
128   Singleton<Watchdog> watchdog(nullptr, nullptr, &vault);
129   Singleton<Watchdog> named_watchdog("named", nullptr, nullptr, &vault);
130   EXPECT_EQ(vault.registeredSingletonCount(), 2);
131   vault.registrationComplete();
132
133   EXPECT_NE(watchdog.ptr(), nullptr);
134   EXPECT_EQ(watchdog.ptr(), Singleton<Watchdog>::get(&vault));
135   EXPECT_NE(watchdog.ptr(), named_watchdog.ptr());
136   EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
137   EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
138 }
139
140 TEST(Singleton, NamedUsage) {
141   SingletonVault vault;
142
143   EXPECT_EQ(vault.registeredSingletonCount(), 0);
144
145   // Define two named Watchdog singletons and one unnamed singleton.
146   Singleton<Watchdog> watchdog1_singleton(
147       "watchdog1", nullptr, nullptr, &vault);
148   EXPECT_EQ(vault.registeredSingletonCount(), 1);
149   Singleton<Watchdog> watchdog2_singleton(
150       "watchdog2", nullptr, nullptr, &vault);
151   EXPECT_EQ(vault.registeredSingletonCount(), 2);
152   Singleton<Watchdog> watchdog3_singleton(nullptr, nullptr, &vault);
153   EXPECT_EQ(vault.registeredSingletonCount(), 3);
154
155   vault.registrationComplete();
156
157   // Verify our three singletons are distinct and non-nullptr.
158   Watchdog* s1 = Singleton<Watchdog>::get("watchdog1", &vault);
159   EXPECT_EQ(s1, watchdog1_singleton.ptr());
160   Watchdog* s2 = Singleton<Watchdog>::get("watchdog2", &vault);
161   EXPECT_EQ(s2, watchdog2_singleton.ptr());
162   EXPECT_NE(s1, s2);
163   Watchdog* s3 = Singleton<Watchdog>::get(&vault);
164   EXPECT_EQ(s3, watchdog3_singleton.ptr());
165   EXPECT_NE(s3, s1);
166   EXPECT_NE(s3, s2);
167
168   // Verify the "default" singleton is the same as the empty string
169   // singleton.
170   Watchdog* s4 = Singleton<Watchdog>::get("", &vault);
171   EXPECT_EQ(s4, watchdog3_singleton.ptr());
172 }
173
174 // Some pathological cases such as getting unregistered singletons,
175 // double registration, etc.
176 TEST(Singleton, NaughtyUsage) {
177   SingletonVault vault(SingletonVault::Type::Strict);
178   vault.registrationComplete();
179
180   // Unregistered.
181   EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
182   EXPECT_THROW(Singleton<Watchdog>::get(&vault), std::out_of_range);
183
184   // Registring singletons after registrationComplete called.
185   EXPECT_THROW([&vault]() {
186                  Singleton<Watchdog> watchdog_singleton(
187                      nullptr, nullptr, &vault);
188                }(),
189                std::logic_error);
190
191   SingletonVault vault_2(SingletonVault::Type::Strict);
192   EXPECT_THROW(Singleton<Watchdog>::get(&vault_2), std::logic_error);
193   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault_2);
194   // double registration
195   EXPECT_THROW([&vault_2]() {
196                  Singleton<Watchdog> watchdog_singleton(
197                      nullptr, nullptr, &vault_2);
198                }(),
199                std::logic_error);
200   vault_2.destroyInstances();
201   // double registration after destroy
202   EXPECT_THROW([&vault_2]() {
203                  Singleton<Watchdog> watchdog_singleton(
204                      nullptr, nullptr, &vault_2);
205                }(),
206                std::logic_error);
207 }
208
209 TEST(Singleton, SharedPtrUsage) {
210   SingletonVault vault;
211
212   EXPECT_EQ(vault.registeredSingletonCount(), 0);
213   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
214   EXPECT_EQ(vault.registeredSingletonCount(), 1);
215
216   Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
217   EXPECT_EQ(vault.registeredSingletonCount(), 2);
218
219   Singleton<Watchdog> named_watchdog_singleton(
220       "a_name", nullptr, nullptr, &vault);
221   vault.registrationComplete();
222
223   Watchdog* s1 = Singleton<Watchdog>::get(&vault);
224   EXPECT_NE(s1, nullptr);
225
226   Watchdog* s2 = Singleton<Watchdog>::get(&vault);
227   EXPECT_NE(s2, nullptr);
228
229   EXPECT_EQ(s1, s2);
230
231   auto weak_s1 = Singleton<Watchdog>::get_weak(&vault);
232   auto shared_s1 = weak_s1.lock();
233   EXPECT_EQ(shared_s1.get(), s1);
234   EXPECT_EQ(shared_s1.use_count(), 2);
235
236   {
237     auto named_weak_s1 = Singleton<Watchdog>::get_weak("a_name", &vault);
238     auto locked = named_weak_s1.lock();
239     EXPECT_NE(locked.get(), shared_s1.get());
240   }
241
242   LOG(ERROR) << "The following log message regarding ref counts is expected";
243   vault.destroyInstances();
244   EXPECT_EQ(vault.registeredSingletonCount(), 3);
245   EXPECT_EQ(vault.livingSingletonCount(), 0);
246
247   EXPECT_EQ(shared_s1.use_count(), 1);
248   EXPECT_EQ(shared_s1.get(), s1);
249
250   auto locked_s1 = weak_s1.lock();
251   EXPECT_EQ(locked_s1.get(), s1);
252   EXPECT_EQ(shared_s1.use_count(), 2);
253   locked_s1.reset();
254   EXPECT_EQ(shared_s1.use_count(), 1);
255
256   // Track serial number rather than pointer since the memory could be
257   // re-used when we create new_s1.
258   auto old_serial = shared_s1->serial_number;
259   shared_s1.reset();
260   locked_s1 = weak_s1.lock();
261   EXPECT_TRUE(weak_s1.expired());
262
263   auto empty_s1 = Singleton<Watchdog>::get_weak(&vault);
264   EXPECT_FALSE(empty_s1.lock());
265
266   vault.reenableInstances();
267
268   // Singleton should be re-created only after reenableInstances() was called.
269   Watchdog* new_s1 = Singleton<Watchdog>::get(&vault);
270   EXPECT_NE(new_s1->serial_number, old_serial);
271 }
272
273 // Some classes to test singleton dependencies.  NeedySingleton has a
274 // dependency on NeededSingleton, which happens during its
275 // construction.
276 SingletonVault needy_vault;
277
278 struct NeededSingleton {};
279 struct NeedySingleton {
280   NeedySingleton() {
281     auto unused = Singleton<NeededSingleton>::get(&needy_vault);
282     EXPECT_NE(unused, nullptr);
283   }
284 };
285
286 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
287 SingletonVault self_needy_vault;
288 struct SelfNeedySingleton {
289   SelfNeedySingleton() {
290     auto unused = Singleton<SelfNeedySingleton>::get(&self_needy_vault);
291     EXPECT_NE(unused, nullptr);
292   }
293 };
294
295 TEST(Singleton, SingletonDependencies) {
296   Singleton<NeededSingleton> needed_singleton(nullptr, nullptr, &needy_vault);
297   Singleton<NeedySingleton> needy_singleton(nullptr, nullptr, &needy_vault);
298   needy_vault.registrationComplete();
299
300   EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
301   EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
302
303   auto needy = Singleton<NeedySingleton>::get(&needy_vault);
304   EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
305
306   Singleton<SelfNeedySingleton> self_needy_singleton(
307       nullptr, nullptr, &self_needy_vault);
308   self_needy_vault.registrationComplete();
309   EXPECT_THROW([]() {
310                  Singleton<SelfNeedySingleton>::get(&self_needy_vault);
311                }(),
312                std::out_of_range);
313 }
314
315 // A test to ensure multiple threads contending on singleton creation
316 // properly wait for creation rather than thinking it is a circular
317 // dependency.
318 class Slowpoke : public Watchdog {
319  public:
320   Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
321 };
322
323 TEST(Singleton, SingletonConcurrency) {
324   SingletonVault vault;
325   Singleton<Slowpoke> slowpoke_singleton(nullptr, nullptr, &vault);
326   vault.registrationComplete();
327
328   std::mutex gatekeeper;
329   gatekeeper.lock();
330   auto func = [&vault, &gatekeeper]() {
331     gatekeeper.lock();
332     gatekeeper.unlock();
333     auto unused = Singleton<Slowpoke>::get(&vault);
334   };
335
336   EXPECT_EQ(vault.livingSingletonCount(), 0);
337   std::vector<std::thread> threads;
338   for (int i = 0; i < 100; ++i) {
339     threads.emplace_back(func);
340   }
341   // If circular dependency checks fail, the unlock would trigger a
342   // crash.  Instead, it succeeds, and we have exactly one living
343   // singleton.
344   gatekeeper.unlock();
345   for (auto& t : threads) {
346     t.join();
347   }
348   EXPECT_EQ(vault.livingSingletonCount(), 1);
349 }
350
351 TEST(Singleton, SingletonConcurrencyStress) {
352   SingletonVault vault;
353   Singleton<Slowpoke> slowpoke_singleton(nullptr, nullptr, &vault);
354
355   std::vector<std::thread> ts;
356   for (size_t i = 0; i < 100; ++i) {
357     ts.emplace_back([&]() {
358         slowpoke_singleton.get_weak(&vault).lock();
359       });
360   }
361
362   for (size_t i = 0; i < 100; ++i) {
363     std::chrono::milliseconds d(20);
364
365     std::this_thread::sleep_for(d);
366     vault.destroyInstances();
367     std::this_thread::sleep_for(d);
368     vault.destroyInstances();
369   }
370
371   for (auto& t : ts) {
372     t.join();
373   }
374 }
375
376 // Benchmarking a normal singleton vs a Meyers singleton vs a Folly
377 // singleton.  Meyers are insanely fast, but (hopefully) Folly
378 // singletons are fast "enough."
379 int* getMeyersSingleton() {
380   static auto ret = new int(0);
381   return ret;
382 }
383
384 int normal_singleton_value = 0;
385 int* getNormalSingleton() {
386   doNotOptimizeAway(&normal_singleton_value);
387   return &normal_singleton_value;
388 }
389
390 // Verify that existing Singleton's can be overridden
391 // using the make_mock functionality.
392 TEST(Singleton, make_mock) {
393   SingletonVault vault(SingletonVault::Type::Strict);
394   Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
395   vault.registrationComplete();
396
397   // Registring singletons after registrationComplete called works
398   // with make_mock (but not with Singleton ctor).
399   EXPECT_EQ(vault.registeredSingletonCount(), 1);
400   int serial_count_first = Singleton<Watchdog>::get(&vault)->serial_number;
401
402   // Override existing mock using make_mock.
403   Singleton<Watchdog>::make_mock(nullptr, nullptr, &vault);
404
405   EXPECT_EQ(vault.registeredSingletonCount(), 1);
406   int serial_count_mock = Singleton<Watchdog>::get(&vault)->serial_number;
407
408   // If serial_count value is the same, then singleton was not replaced.
409   EXPECT_NE(serial_count_first, serial_count_mock);
410 }
411
412 struct BenchmarkSingleton {
413   int val = 0;
414 };
415
416 BENCHMARK(NormalSingleton, n) {
417   for (size_t i = 0; i < n; ++i) {
418     doNotOptimizeAway(getNormalSingleton());
419   }
420 }
421
422 BENCHMARK_RELATIVE(MeyersSingleton, n) {
423   for (size_t i = 0; i < n; ++i) {
424     doNotOptimizeAway(getMeyersSingleton());
425   }
426 }
427
428 BENCHMARK_RELATIVE(FollySingletonSlow, n) {
429   SingletonVault benchmark_vault;
430   Singleton<BenchmarkSingleton> benchmark_singleton(
431       nullptr, nullptr, &benchmark_vault);
432   benchmark_vault.registrationComplete();
433
434   for (size_t i = 0; i < n; ++i) {
435     doNotOptimizeAway(Singleton<BenchmarkSingleton>::get(&benchmark_vault));
436   }
437 }
438
439 BENCHMARK_RELATIVE(FollySingletonFast, n) {
440   SingletonVault benchmark_vault;
441   Singleton<BenchmarkSingleton> benchmark_singleton(
442       nullptr, nullptr, &benchmark_vault);
443   benchmark_vault.registrationComplete();
444
445   for (size_t i = 0; i < n; ++i) {
446     doNotOptimizeAway(benchmark_singleton.get_fast());
447   }
448 }
449
450 BENCHMARK_RELATIVE(FollySingletonFastWeak, n) {
451   SingletonVault benchmark_vault;
452   Singleton<BenchmarkSingleton> benchmark_singleton(
453       nullptr, nullptr, &benchmark_vault);
454   benchmark_vault.registrationComplete();
455
456   for (size_t i = 0; i < n; ++i) {
457     benchmark_singleton.get_weak_fast();
458   }
459 }
460
461 int main(int argc, char* argv[]) {
462   testing::InitGoogleTest(&argc, argv);
463   google::InitGoogleLogging(argv[0]);
464   google::ParseCommandLineFlags(&argc, &argv, true);
465
466   SingletonVault::singleton()->registrationComplete();
467
468   auto ret = RUN_ALL_TESTS();
469   if (!ret) {
470     folly::runBenchmarksOnFlag();
471   }
472   return ret;
473 }