4cf94c24a1a172d6f5f60772690261678bb19dd5
[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
73 void benchmarkSharedPtrCopy(size_t numThreads, size_t iters) {
74   auto p = std::make_shared<int>(1);
75   parallelRun([&] { return p; }, numThreads, iters);
76 }
77
78 void benchmarkWeakPtrLock(size_t numThreads, size_t iters) {
79   auto p = std::make_shared<int>(1);
80   std::weak_ptr<int> wp = p;
81   parallelRun([&] { return wp.lock(); }, numThreads, iters);
82 }
83
84 void benchmarkAtomicSharedPtrCopy(size_t numThreads, size_t iters) {
85   auto s = std::make_shared<int>(1);
86   folly::atomic_shared_ptr<int> p;
87   p.store(s);
88   parallelRun([&] { return p.load(); }, numThreads, iters);
89 }
90
91 void benchmarkCoreCachedSharedPtrGet(size_t numThreads, size_t iters) {
92   folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1));
93   parallelRun([&] { return p.get(); }, numThreads, iters);
94 }
95
96 void benchmarkCoreCachedWeakPtrLock(size_t numThreads, size_t iters) {
97   folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1));
98   folly::CoreCachedWeakPtr<int> wp(p);
99   parallelRun([&] { return wp.get().lock(); }, numThreads, iters);
100 }
101
102 void benchmarkAtomicCoreCachedSharedPtrGet(size_t numThreads, size_t iters) {
103   folly::AtomicCoreCachedSharedPtr<int> p(std::make_shared<int>(1));
104   parallelRun([&] { return p.get(); }, numThreads, iters);
105 }
106
107 } // namespace
108
109 BENCHMARK(SharedPtrSingleThread, n) {
110   benchmarkSharedPtrCopy(1, n);
111 }
112 BENCHMARK(WeakPtrSingleThread, n) {
113   benchmarkWeakPtrLock(1, n);
114 }
115 BENCHMARK(AtomicSharedPtrSingleThread, n) {
116   benchmarkAtomicSharedPtrCopy(1, n);
117 }
118 BENCHMARK(CoreCachedSharedPtrSingleThread, n) {
119   benchmarkCoreCachedSharedPtrGet(1, n);
120 }
121 BENCHMARK(CoreCachedWeakPtrSingleThread, n) {
122   benchmarkCoreCachedWeakPtrLock(1, n);
123 }
124 BENCHMARK(AtomicCoreCachedSharedPtrSingleThread, n) {
125   benchmarkAtomicCoreCachedSharedPtrGet(1, n);
126 }
127
128 BENCHMARK_DRAW_LINE();
129
130 BENCHMARK(SharedPtr4Threads, n) {
131   benchmarkSharedPtrCopy(4, n);
132 }
133 BENCHMARK(WeakPtr4Threads, n) {
134   benchmarkWeakPtrLock(4, n);
135 }
136 BENCHMARK(AtomicSharedPtr4Threads, n) {
137   benchmarkAtomicSharedPtrCopy(4, n);
138 }
139 BENCHMARK(CoreCachedSharedPtr4Threads, n) {
140   benchmarkCoreCachedSharedPtrGet(4, n);
141 }
142 BENCHMARK(CoreCachedWeakPtr4Threads, n) {
143   benchmarkCoreCachedWeakPtrLock(4, n);
144 }
145 BENCHMARK(AtomicCoreCachedSharedPtr4Threads, n) {
146   benchmarkAtomicCoreCachedSharedPtrGet(4, n);
147 }
148
149 BENCHMARK_DRAW_LINE();
150
151 BENCHMARK(SharedPtr16Threads, n) {
152   benchmarkSharedPtrCopy(16, n);
153 }
154 BENCHMARK(WeakPtr16Threads, n) {
155   benchmarkWeakPtrLock(16, n);
156 }
157 BENCHMARK(AtomicSharedPtr16Threads, n) {
158   benchmarkAtomicSharedPtrCopy(16, n);
159 }
160 BENCHMARK(CoreCachedSharedPtr16Threads, n) {
161   benchmarkCoreCachedSharedPtrGet(16, n);
162 }
163 BENCHMARK(CoreCachedWeakPtr16Threads, n) {
164   benchmarkCoreCachedWeakPtrLock(16, n);
165 }
166 BENCHMARK(AtomicCoreCachedSharedPtr16Threads, n) {
167   benchmarkAtomicCoreCachedSharedPtrGet(16, n);
168 }
169
170 BENCHMARK_DRAW_LINE();
171
172 BENCHMARK(SharedPtrSingleThreadReset, n) {
173   auto p = std::make_shared<int>(1);
174   parallelRun([&] { p = std::make_shared<int>(1); }, 1, n);
175 }
176 BENCHMARK(AtomicSharedPtrSingleThreadReset, n) {
177   auto s = std::make_shared<int>(1);
178   folly::atomic_shared_ptr<int> p;
179   p.store(s);
180   parallelRun([&] { p.store(std::make_shared<int>(1)); }, 1, n);
181 }
182 BENCHMARK(CoreCachedSharedPtrSingleThreadReset, n) {
183   folly::CoreCachedSharedPtr<int> p(std::make_shared<int>(1));
184   parallelRun([&] { p.reset(std::make_shared<int>(1)); }, 1, n);
185 }
186 BENCHMARK(AtomicCoreCachedSharedPtrSingleThreadReset, n) {
187   folly::AtomicCoreCachedSharedPtr<int> p(std::make_shared<int>(1));
188   parallelRun([&] { p.reset(std::make_shared<int>(1)); }, 1, n);
189 }
190
191 int main(int argc, char** argv) {
192   testing::InitGoogleTest(&argc, argv);
193   gflags::ParseCommandLineFlags(&argc, &argv, true);
194
195   auto ret = RUN_ALL_TESTS();
196   if (ret == 0 && FLAGS_benchmark) {
197     folly::runBenchmarks();
198   }
199
200   return ret;
201 }