/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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. */ #include #include #include #include #include #include #include FOLLY_GNU_DISABLE_WARNING("-Wdeprecated-declarations") 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 f) { std::vector 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 using SingletonBenchmark = Singleton; struct GetTag {}; struct TryGetTag {}; struct TryGetFastTag {}; SingletonBenchmark benchmark_singleton_get; SingletonBenchmark benchmark_singleton_try_get; SingletonBenchmark benchmark_singleton_try_get_fast; void follySingletonRaw(size_t n) { for (size_t i = 0; i < n; ++i) { SingletonBenchmark::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::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::try_get_fast(); } } BENCHMARK(FollySingletonTryGetFast, n) { follySingletonTryGetFast(n); } BENCHMARK(FollySingletonTryGetFast4Threads, n) { run4Threads([=]() { follySingletonTryGetFast(n); }); } void follySingletonThreadLocal(size_t n) { for (size_t i = 0; i < n; ++i) { folly::SingletonThreadLocal::get().val++; } } BENCHMARK(FollySingletonThreadLocal, n) { follySingletonThreadLocal(n); } BENCHMARK(FollySingletonThreadLocal4Threads, n) { run4Threads([=]() { follySingletonThreadLocal(n); }); } LeakySingleton benchmark_leaky_singleton; void follyLeakySingleton(size_t n) { for (size_t i = 0; i < n; ++i) { LeakySingleton::get().val++; } } BENCHMARK(FollyLeakySingleton, n) { follyLeakySingleton(n); } BENCHMARK(FollyLeakySingleton4Threads, n) { run4Threads([=]() { follyLeakySingleton(n); }); } int main(int argc, char** argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); gflags::SetCommandLineOptionWithMode( "bm_min_usec", "100000", gflags::SET_FLAG_IF_DEFAULT); folly::SingletonVault::singleton()->registrationComplete(); folly::runBenchmarks(); return 0; }