2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/experimental/Singleton.h>
19 #include <folly/Benchmark.h>
21 #include <glog/logging.h>
22 #include <gtest/gtest.h>
24 using namespace folly;
26 // A simple class that tracks how often instances of the class and
27 // subclasses are created, and the ordering. Also tracks a global
28 // unique counter for each object.
29 std::atomic<size_t> global_counter(19770326);
31 static std::vector<Watchdog*> creation_order;
32 Watchdog() : serial_number(++global_counter) {
33 creation_order.push_back(this);
37 if (creation_order.back() != this) {
38 throw std::out_of_range("Watchdog destruction order mismatch");
40 creation_order.pop_back();
43 const size_t serial_number;
45 Watchdog(const Watchdog&) = delete;
46 Watchdog& operator=(const Watchdog&) = delete;
47 Watchdog(Watchdog&&) noexcept = default;
50 std::vector<Watchdog*> Watchdog::creation_order;
52 // Some basic types we use for tracking.
53 struct ChildWatchdog : public Watchdog {};
54 struct GlobalWatchdog : public Watchdog {};
55 struct UnregisteredWatchdog : public Watchdog {};
58 Singleton<GlobalWatchdog> global_watchdog;
61 // Test basic global usage (the default way singletons will generally
63 TEST(Singleton, BasicGlobalUsage) {
64 EXPECT_EQ(Watchdog::creation_order.size(), 0);
65 EXPECT_EQ(SingletonVault::singleton()->registeredSingletonCount(), 1);
66 EXPECT_EQ(SingletonVault::singleton()->livingSingletonCount(), 0);
67 auto wd1 = Singleton<GlobalWatchdog>::get();
68 EXPECT_NE(wd1, nullptr);
69 EXPECT_EQ(Watchdog::creation_order.size(), 1);
70 auto wd2 = Singleton<GlobalWatchdog>::get();
71 EXPECT_NE(wd2, nullptr);
73 EXPECT_EQ(Watchdog::creation_order.size(), 1);
74 SingletonVault::singleton()->destroyInstances();
75 EXPECT_EQ(Watchdog::creation_order.size(), 0);
78 TEST(Singleton, MissingSingleton) {
79 EXPECT_THROW([]() { auto u = Singleton<UnregisteredWatchdog>::get(); }(),
83 // Exercise some basic codepaths ensuring registration order and
84 // destruction order happen as expected, that instances are created
85 // when expected, etc etc.
86 TEST(Singleton, BasicUsage) {
89 EXPECT_EQ(vault.registeredSingletonCount(), 0);
90 Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
91 EXPECT_EQ(vault.registeredSingletonCount(), 1);
93 Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
94 EXPECT_EQ(vault.registeredSingletonCount(), 2);
96 vault.registrationComplete();
98 Watchdog* s1 = Singleton<Watchdog>::get(&vault);
99 EXPECT_NE(s1, nullptr);
101 Watchdog* s2 = Singleton<Watchdog>::get(&vault);
102 EXPECT_NE(s2, nullptr);
106 auto s3 = Singleton<ChildWatchdog>::get(&vault);
107 EXPECT_NE(s3, nullptr);
110 EXPECT_EQ(vault.registeredSingletonCount(), 2);
111 EXPECT_EQ(vault.livingSingletonCount(), 2);
113 vault.destroyInstances();
114 EXPECT_EQ(vault.registeredSingletonCount(), 2);
115 EXPECT_EQ(vault.livingSingletonCount(), 0);
118 // Some pathological cases such as getting unregistered singletons,
119 // double registration, etc.
120 TEST(Singleton, NaughtyUsage) {
121 SingletonVault vault;
122 vault.registrationComplete();
125 EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
126 EXPECT_THROW(Singleton<Watchdog>::get(&vault), std::out_of_range);
128 // Registring singletons after registrationComplete called.
129 EXPECT_THROW([&vault]() {
130 Singleton<Watchdog> watchdog_singleton(
131 nullptr, nullptr, &vault);
135 EXPECT_THROW([]() { Singleton<Watchdog> watchdog_singleton; }(),
138 SingletonVault vault_2;
139 EXPECT_THROW(Singleton<Watchdog>::get(&vault_2), std::logic_error);
140 Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault_2);
141 // double registration
142 EXPECT_THROW([&vault_2]() {
143 Singleton<Watchdog> watchdog_singleton(
144 nullptr, nullptr, &vault_2);
147 vault_2.destroyInstances();
148 // double registration after destroy
149 EXPECT_THROW([&vault_2]() {
150 Singleton<Watchdog> watchdog_singleton(
151 nullptr, nullptr, &vault_2);
156 TEST(Singleton, SharedPtrUsage) {
157 SingletonVault vault;
159 EXPECT_EQ(vault.registeredSingletonCount(), 0);
160 Singleton<Watchdog> watchdog_singleton(nullptr, nullptr, &vault);
161 EXPECT_EQ(vault.registeredSingletonCount(), 1);
163 Singleton<ChildWatchdog> child_watchdog_singleton(nullptr, nullptr, &vault);
164 EXPECT_EQ(vault.registeredSingletonCount(), 2);
166 vault.registrationComplete();
168 Watchdog* s1 = Singleton<Watchdog>::get(&vault);
169 EXPECT_NE(s1, nullptr);
171 Watchdog* s2 = Singleton<Watchdog>::get(&vault);
172 EXPECT_NE(s2, nullptr);
176 auto weak_s1 = Singleton<Watchdog>::get_weak(&vault);
177 auto shared_s1 = weak_s1.lock();
178 EXPECT_EQ(shared_s1.get(), s1);
179 EXPECT_EQ(shared_s1.use_count(), 2);
181 LOG(ERROR) << "The following log message regarding ref counts is expected";
182 vault.destroyInstances();
183 EXPECT_EQ(vault.registeredSingletonCount(), 2);
184 EXPECT_EQ(vault.livingSingletonCount(), 0);
186 EXPECT_EQ(shared_s1.use_count(), 1);
187 EXPECT_EQ(shared_s1.get(), s1);
189 auto locked_s1 = weak_s1.lock();
190 EXPECT_EQ(locked_s1.get(), s1);
191 EXPECT_EQ(shared_s1.use_count(), 2);
193 EXPECT_EQ(shared_s1.use_count(), 1);
195 // Track serial number rather than pointer since the memory could be
196 // re-used when we create new_s1.
197 auto old_serial = shared_s1->serial_number;
199 locked_s1 = weak_s1.lock();
200 EXPECT_TRUE(weak_s1.expired());
202 Watchdog* new_s1 = Singleton<Watchdog>::get(&vault);
203 EXPECT_NE(new_s1->serial_number, old_serial);
206 // Some classes to test singleton dependencies. NeedySingleton has a
207 // dependency on NeededSingleton, which happens during its
209 SingletonVault needy_vault;
211 struct NeededSingleton {};
212 struct NeedySingleton {
214 auto unused = Singleton<NeededSingleton>::get(&needy_vault);
215 EXPECT_NE(unused, nullptr);
219 // Ensure circular dependencies fail -- a singleton that needs itself, whoops.
220 SingletonVault self_needy_vault;
221 struct SelfNeedySingleton {
222 SelfNeedySingleton() {
223 auto unused = Singleton<SelfNeedySingleton>::get(&self_needy_vault);
224 EXPECT_NE(unused, nullptr);
228 TEST(Singleton, SingletonDependencies) {
229 Singleton<NeededSingleton> needed_singleton(nullptr, nullptr, &needy_vault);
230 Singleton<NeedySingleton> needy_singleton(nullptr, nullptr, &needy_vault);
231 needy_vault.registrationComplete();
233 EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
234 EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
236 auto needy = Singleton<NeedySingleton>::get(&needy_vault);
237 EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
239 Singleton<SelfNeedySingleton> self_needy_singleton(
240 nullptr, nullptr, &self_needy_vault);
241 self_needy_vault.registrationComplete();
243 Singleton<SelfNeedySingleton>::get(&self_needy_vault);
248 // Benchmarking a normal singleton vs a Meyers singleton vs a Folly
249 // singleton. Meyers are insanely fast, but (hopefully) Folly
250 // singletons are fast "enough."
251 int* getMeyersSingleton() {
252 static auto ret = new int(0);
256 int normal_singleton_value = 0;
257 int* getNormalSingleton() {
258 doNotOptimizeAway(&normal_singleton_value);
259 return &normal_singleton_value;
262 struct BenchmarkSingleton {
266 BENCHMARK(NormalSingleton, n) {
267 for (int i = 0; i < n; ++i) {
268 doNotOptimizeAway(getNormalSingleton());
272 BENCHMARK_RELATIVE(MeyersSingleton, n) {
273 for (int i = 0; i < n; ++i) {
274 doNotOptimizeAway(getMeyersSingleton());
278 BENCHMARK_RELATIVE(FollySingleton, n) {
279 SingletonVault benchmark_vault;
280 Singleton<BenchmarkSingleton> benchmark_singleton(
281 nullptr, nullptr, &benchmark_vault);
282 benchmark_vault.registrationComplete();
284 for (int i = 0; i < n; ++i) {
285 doNotOptimizeAway(Singleton<BenchmarkSingleton>::get(&benchmark_vault));
289 int main(int argc, char* argv[]) {
290 testing::InitGoogleTest(&argc, argv);
291 google::InitGoogleLogging(argv[0]);
292 google::ParseCommandLineFlags(&argc, &argv, true);
294 SingletonVault::singleton()->registrationComplete();
296 auto ret = RUN_ALL_TESTS();
298 folly::runBenchmarksOnFlag();