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