2 * Copyright 2017-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/synchronization/Rcu.h>
21 #include <glog/logging.h>
23 #include <folly/Benchmark.h>
24 #include <folly/Random.h>
25 #include <folly/portability/GFlags.h>
26 #include <folly/portability/GTest.h>
27 #include <folly/synchronization/Baton.h>
29 using namespace folly;
31 DEFINE_int64(iters, 100000, "Number of iterations");
32 DEFINE_int64(threads, 32, "Number of threads");
34 TEST(RcuTest, Basic) {
35 auto foo = new int(2);
43 des(bool* d) : d_(d) {}
49 TEST(RcuTest, Guard) {
51 auto foo = new des(&del);
60 auto start = std::chrono::steady_clock::now();
64 auto diff = std::chrono::steady_clock::now() - start;
66 "Total time %li ns \n",
67 std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count() /
71 TEST(RcuTest, ResetPerf) {
73 auto start = std::chrono::steady_clock::now();
75 rcu_retire<int>(nullptr, [](int*) {});
77 auto diff = std::chrono::steady_clock::now() - start;
79 "Total time %li ns \n",
80 std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count() /
84 TEST(RcuTest, SlowReader) {
89 t = std::thread([&]() { synchronize_rcu(); });
90 usleep(100); // Wait for synchronize to start
95 rcu_reader tryretire(des* obj) {
101 TEST(RcuTest, CopyGuard) {
103 auto foo = new des(&del);
105 auto res = tryretire(foo);
112 TEST(RcuTest, Stress) {
113 std::vector<std::thread> threads;
114 constexpr uint32_t sz = 1000;
115 std::atomic<int*> ints[sz];
116 for (uint i = 0; i < sz; i++) {
117 ints[i].store(new int(0));
119 for (int th = 0; th < FLAGS_threads; th++) {
120 threads.push_back(std::thread([&]() {
121 for (int i = 0; i < FLAGS_iters / 100; i++) {
125 for (uint j = 0; j < sz; j++) {
126 ptrs[j] = ints[j].load(std::memory_order_acquire);
128 for (uint j = 0; j < sz; j++) {
135 std::atomic<bool> done{false};
136 std::thread updater([&]() {
137 while (!done.load()) {
138 auto newint = new int(0);
139 auto oldint = ints[folly::Random::rand32() % sz].exchange(newint);
140 rcu_retire<int>(oldint, [](int* obj) {
141 *obj = folly::Random::rand32();
146 for (auto& t : threads) {
153 TEST(RcuTest, Synchronize) {
154 std::vector<std::thread> threads;
155 for (int th = 0; th < FLAGS_threads; th++) {
156 threads.push_back(std::thread([&]() {
157 for (int i = 0; i < 10; i++) {
162 for (auto& t : threads) {
167 TEST(RcuTest, NewDomainTest) {
169 rcu_domain<UniqueTag> newdomain(nullptr);
173 TEST(RcuTest, MovableReader) {
176 rcu_reader f(std::move(g));
180 rcu_reader g(std::defer_lock);
187 TEST(RcuTest, SynchronizeInCall) {
188 rcu_default_domain()->call([]() { synchronize_rcu(); });
192 TEST(RcuTest, MoveReaderBetweenThreads) {
194 std::thread t([f = std::move(g)] {});
199 TEST(RcuTest, ForkTest) {
202 std::thread t([&]() {
203 epoch = rcu_default_domain()->lock_shared();
211 rcu_default_domain()->unlock_shared(std::move(epoch));
214 auto pid2 = wait(&status);
215 EXPECT_EQ(status, 0);
216 EXPECT_EQ(pid, pid2);
220 exit(0); // Do not print gtest results
224 TEST(RcuTest, CoreLocalList) {
226 folly::detail::ThreadCachedLists<TTag> lists;
228 std::vector<std::thread> threads;
229 std::atomic<int> done{0};
230 for (int tr = 0; tr < numthreads; tr++) {
231 threads.push_back(std::thread([&]() {
232 for (int i = 0; i < FLAGS_iters; i++) {
233 auto node = new folly::detail::ThreadCachedListsBase::Node;
239 while (done.load() != numthreads) {
240 folly::detail::ThreadCachedLists<TTag>::ListHead list{};
242 list.forEach([](folly::detail::ThreadCachedLists<TTag>::Node* node) {
246 for (auto& thread : threads) {
251 TEST(RcuTest, ThreadDeath) {
254 auto foo = new des(&del);
262 TEST(RcuTest, RcuObjBase) {
263 bool retired = false;
264 struct base_test : rcu_obj_base<base_test> {
266 base_test(bool* ret) : ret_(ret) {}
272 auto foo = new base_test(&retired);
275 EXPECT_TRUE(retired);