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 | |
30 | TEST(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 | |
55 | namespace { |
56 | |
57 | template <class Operation> |
58 | void 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 | |
77 | void benchmarkSharedPtrCopy(size_t numThreads, size_t iters) { |
78 | auto p = std::make_shared<int>(1); |
79 | parallelRun([&] { return p; }, numThreads, iters); |
80 | } |
81 | |
82 | void 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 | |
88 | void 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 | |
95 | void 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 | |
100 | void 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 | |
106 | void 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 | |
113 | BENCHMARK(SharedPtrSingleThread, n) { |
114 | benchmarkSharedPtrCopy(1, n); |
115 | } |
116 | BENCHMARK(WeakPtrSingleThread, n) { |
117 | benchmarkWeakPtrLock(1, n); |
118 | } |
119 | BENCHMARK(AtomicSharedPtrSingleThread, n) { |
120 | benchmarkAtomicSharedPtrCopy(1, n); |
121 | } |
122 | BENCHMARK(CoreCachedSharedPtrSingleThread, n) { |
123 | benchmarkCoreCachedSharedPtrGet(1, n); |
124 | } |
125 | BENCHMARK(CoreCachedWeakPtrSingleThread, n) { |
126 | benchmarkCoreCachedWeakPtrLock(1, n); |
127 | } |
128 | BENCHMARK(AtomicCoreCachedSharedPtrSingleThread, n) { |
129 | benchmarkAtomicCoreCachedSharedPtrGet(1, n); |
130 | } |
131 | |
132 | BENCHMARK_DRAW_LINE(); |
133 | |
134 | BENCHMARK(SharedPtr4Threads, n) { |
135 | benchmarkSharedPtrCopy(4, n); |
136 | } |
137 | BENCHMARK(WeakPtr4Threads, n) { |
138 | benchmarkWeakPtrLock(4, n); |
139 | } |
140 | BENCHMARK(AtomicSharedPtr4Threads, n) { |
141 | benchmarkAtomicSharedPtrCopy(4, n); |
142 | } |
143 | BENCHMARK(CoreCachedSharedPtr4Threads, n) { |
144 | benchmarkCoreCachedSharedPtrGet(4, n); |
145 | } |
146 | BENCHMARK(CoreCachedWeakPtr4Threads, n) { |
147 | benchmarkCoreCachedWeakPtrLock(4, n); |
148 | } |
149 | BENCHMARK(AtomicCoreCachedSharedPtr4Threads, n) { |
150 | benchmarkAtomicCoreCachedSharedPtrGet(4, n); |
151 | } |
152 | |
153 | BENCHMARK_DRAW_LINE(); |
154 | |
155 | BENCHMARK(SharedPtr16Threads, n) { |
156 | benchmarkSharedPtrCopy(16, n); |
157 | } |
158 | BENCHMARK(WeakPtr16Threads, n) { |
159 | benchmarkWeakPtrLock(16, n); |
160 | } |
161 | BENCHMARK(AtomicSharedPtr16Threads, n) { |
162 | benchmarkAtomicSharedPtrCopy(16, n); |
163 | } |
164 | BENCHMARK(CoreCachedSharedPtr16Threads, n) { |
165 | benchmarkCoreCachedSharedPtrGet(16, n); |
166 | } |
167 | BENCHMARK(CoreCachedWeakPtr16Threads, n) { |
168 | benchmarkCoreCachedWeakPtrLock(16, n); |
169 | } |
170 | BENCHMARK(AtomicCoreCachedSharedPtr16Threads, n) { |
171 | benchmarkAtomicCoreCachedSharedPtrGet(16, n); |
172 | } |
173 | |
174 | BENCHMARK_DRAW_LINE(); |
175 | |
176 | BENCHMARK(SharedPtrSingleThreadReset, n) { |
177 | auto p = std::make_shared<int>(1); |
178 | parallelRun([&] { p = std::make_shared<int>(1); }, 1, n); |
179 | } |
180 | BENCHMARK(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 | } |
186 | BENCHMARK(CoreCachedSharedPtrSingleThreadReset, n) { |
187 | folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1)); |
188 | parallelRun([&] { p.reset(std::make_shared<int>(1)); }, 1, n); |
189 | } |
190 | BENCHMARK(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 | |
195 | int 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 | |