1/*
2 * Copyright 2017-present 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// AtomicSharedPtr-detail.h only works with libstdc++, so skip these tests for
18// other vendors
19#ifdef FOLLY_USE_LIBSTDCPP
20
21#include <memory>
22#include <thread>
23#include <vector>
24
25#include <folly/Benchmark.h>
26#include <folly/Portability.h>
27#include <folly/concurrency/CoreCachedSharedPtr.h>
28#include <folly/portability/GTest.h>
29
30TEST(CoreCachedSharedPtr, Basic) {
31 auto p = std::make_shared<int>(1);
32 std::weak_ptr<int> wp(p);
33
34 folly::CoreCachedSharedPtr<int> cached(p);
35 folly::CoreCachedWeakPtr<int> wcached(cached);
36
37 std::shared_ptr<int> p2 = cached.get();
38 std::weak_ptr<int> wp2 = wcached.get();
39 ASSERT_TRUE(p2 != nullptr);
40 ASSERT_EQ(*p2, 1);
41 ASSERT_FALSE(wp2.expired());
42
43 p.reset();
44 cached.reset();
45 // p2 should survive.
46 ASSERT_FALSE(wp.expired());
47 // Here we don't know anything about wp2: could be expired even if
48 // there is a living reference to the main object.
49
50 p2.reset();
51 ASSERT_TRUE(wp.expired());
52 ASSERT_TRUE(wp2.expired());
53}
54
55namespace {
56
57template <class Operation>
58void parallelRun(Operation op, size_t numThreads, size_t iters) {
59 std::vector<std::thread> threads;
60
61 // Prevent the compiler from hoisting code out of the loop.
62 auto opNoinline = [&]() FOLLY_NOINLINE { op(); };
63
64 for (size_t t = 0; t < numThreads; ++t) {
65 threads.emplace_back([&] {
66 for (size_t i = 0; i < iters; ++i) {
67 opNoinline();
68 }
69 });
70 }
71
72 for (auto& t : threads) {
73 t.join();
74 }
75}
76
77void benchmarkSharedPtrCopy(size_t numThreads, size_t iters) {
78 auto p = std::make_shared<int>(1);
79 parallelRun([&] { return p; }, numThreads, iters);
80}
81
82void benchmarkWeakPtrLock(size_t numThreads, size_t iters) {
83 auto p = std::make_shared<int>(1);
84 std::weak_ptr<int> wp = p;
85 parallelRun([&] { return wp.lock(); }, numThreads, iters);
86}
87
88void benchmarkAtomicSharedPtrCopy(size_t numThreads, size_t iters) {
89 auto s = std::make_shared<int>(1);
90 folly::atomic_shared_ptr<int> p;
91 p.store(s);
92 parallelRun([&] { return p.load(); }, numThreads, iters);
93}
94
95void benchmarkCoreCachedSharedPtrGet(size_t numThreads, size_t iters) {
96 folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1));
97 parallelRun([&] { return p.get(); }, numThreads, iters);
98}
99
100void benchmarkCoreCachedWeakPtrLock(size_t numThreads, size_t iters) {
101 folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1));
102 folly::CoreCachedWeakPtr<int> wp(p);
103 parallelRun([&] { return wp.get().lock(); }, numThreads, iters);
104}
105
106void benchmarkAtomicCoreCachedSharedPtrGet(size_t numThreads, size_t iters) {
107 folly::AtomicCoreCachedSharedPtr<int> p(std::make_shared<int>(1));
108 parallelRun([&] { return p.get(); }, numThreads, iters);
109}
110
111} // namespace
112
113BENCHMARK(SharedPtrSingleThread, n) {
114 benchmarkSharedPtrCopy(1, n);
115}
116BENCHMARK(WeakPtrSingleThread, n) {
117 benchmarkWeakPtrLock(1, n);
118}
119BENCHMARK(AtomicSharedPtrSingleThread, n) {
120 benchmarkAtomicSharedPtrCopy(1, n);
121}
122BENCHMARK(CoreCachedSharedPtrSingleThread, n) {
123 benchmarkCoreCachedSharedPtrGet(1, n);
124}
125BENCHMARK(CoreCachedWeakPtrSingleThread, n) {
126 benchmarkCoreCachedWeakPtrLock(1, n);
127}
128BENCHMARK(AtomicCoreCachedSharedPtrSingleThread, n) {
129 benchmarkAtomicCoreCachedSharedPtrGet(1, n);
130}
131
132BENCHMARK_DRAW_LINE();
133
134BENCHMARK(SharedPtr4Threads, n) {
135 benchmarkSharedPtrCopy(4, n);
136}
137BENCHMARK(WeakPtr4Threads, n) {
138 benchmarkWeakPtrLock(4, n);
139}
140BENCHMARK(AtomicSharedPtr4Threads, n) {
141 benchmarkAtomicSharedPtrCopy(4, n);
142}
143BENCHMARK(CoreCachedSharedPtr4Threads, n) {
144 benchmarkCoreCachedSharedPtrGet(4, n);
145}
146BENCHMARK(CoreCachedWeakPtr4Threads, n) {
147 benchmarkCoreCachedWeakPtrLock(4, n);
148}
149BENCHMARK(AtomicCoreCachedSharedPtr4Threads, n) {
150 benchmarkAtomicCoreCachedSharedPtrGet(4, n);
151}
152
153BENCHMARK_DRAW_LINE();
154
155BENCHMARK(SharedPtr16Threads, n) {
156 benchmarkSharedPtrCopy(16, n);
157}
158BENCHMARK(WeakPtr16Threads, n) {
159 benchmarkWeakPtrLock(16, n);
160}
161BENCHMARK(AtomicSharedPtr16Threads, n) {
162 benchmarkAtomicSharedPtrCopy(16, n);
163}
164BENCHMARK(CoreCachedSharedPtr16Threads, n) {
165 benchmarkCoreCachedSharedPtrGet(16, n);
166}
167BENCHMARK(CoreCachedWeakPtr16Threads, n) {
168 benchmarkCoreCachedWeakPtrLock(16, n);
169}
170BENCHMARK(AtomicCoreCachedSharedPtr16Threads, n) {
171 benchmarkAtomicCoreCachedSharedPtrGet(16, n);
172}
173
174BENCHMARK_DRAW_LINE();
175
176BENCHMARK(SharedPtrSingleThreadReset, n) {
177 auto p = std::make_shared<int>(1);
178 parallelRun([&] { p = std::make_shared<int>(1); }, 1, n);
179}
180BENCHMARK(AtomicSharedPtrSingleThreadReset, n) {
181 auto s = std::make_shared<int>(1);
182 folly::atomic_shared_ptr<int> p;
183 p.store(s);
184 parallelRun([&] { p.store(std::make_shared<int>(1)); }, 1, n);
185}
186BENCHMARK(CoreCachedSharedPtrSingleThreadReset, n) {
187 folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1));
188 parallelRun([&] { p.reset(std::make_shared<int>(1)); }, 1, n);
189}
190BENCHMARK(AtomicCoreCachedSharedPtrSingleThreadReset, n) {
191 folly::AtomicCoreCachedSharedPtr<int> p(std::make_shared<int>(1));
192 parallelRun([&] { p.reset(std::make_shared<int>(1)); }, 1, n);
193}
194
195int main(int argc, char** argv) {
196 testing::InitGoogleTest(&argc, argv);
197 gflags::ParseCommandLineFlags(&argc, &argv, true);
198
199 auto ret = RUN_ALL_TESTS();
200 if (ret == 0 && FLAGS_benchmark) {
201 folly::runBenchmarks();
202 }
203
204 return ret;
205}
206
207#endif // #ifdef FOLLY_USE_LIBSTDCPP
208