2 * Copyright 2017 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/experimental/hazptr/test/HazptrUse1.h>
17 #include <folly/experimental/hazptr/test/HazptrUse2.h>
18 #include <folly/experimental/hazptr/example/LockFreeLIFO.h>
19 #include <folly/experimental/hazptr/example/SWMRList.h>
20 #include <folly/experimental/hazptr/example/WideCAS.h>
21 #include <folly/experimental/hazptr/debug.h>
22 #include <folly/experimental/hazptr/hazptr.h>
24 #include <folly/portability/GFlags.h>
25 #include <folly/portability/GTest.h>
29 DEFINE_int32(num_threads, 1, "Number of threads");
30 DEFINE_int64(num_reps, 1, "Number of test reps");
31 DEFINE_int64(num_ops, 10, "Number of ops or pairs of ops per rep");
33 using namespace folly::hazptr;
35 class HazptrTest : public testing::Test {
37 HazptrTest() : Test() {
38 DEBUG_PRINT("========== start of test scope");
40 ~HazptrTest() override {
41 DEBUG_PRINT("========== end of test scope");
45 TEST_F(HazptrTest, Test1) {
47 Node1* node0 = (Node1*)malloc(sizeof(Node1));
48 DEBUG_PRINT("=== new node0 " << node0 << " " << sizeof(*node0));
49 Node1* node1 = (Node1*)malloc(sizeof(Node1));
50 DEBUG_PRINT("=== malloc node1 " << node1 << " " << sizeof(*node1));
51 Node1* node2 = (Node1*)malloc(sizeof(Node1));
52 DEBUG_PRINT("=== malloc node2 " << node2 << " " << sizeof(*node2));
53 Node1* node3 = (Node1*)malloc(sizeof(Node1));
54 DEBUG_PRINT("=== malloc node3 " << node3 << " " << sizeof(*node3));
58 std::atomic<Node1*> shared0 = {node0};
59 std::atomic<Node1*> shared1 = {node1};
60 std::atomic<Node1*> shared2 = {node2};
61 std::atomic<Node1*> shared3 = {node3};
63 MyMemoryResource myMr;
64 DEBUG_PRINT("=== myMr " << &myMr);
65 hazptr_domain myDomain0;
66 DEBUG_PRINT("=== myDomain0 " << &myDomain0);
67 hazptr_domain myDomain1(&myMr);
68 DEBUG_PRINT("=== myDomain1 " << &myDomain1);
72 DEBUG_PRINT("=== hptr0");
73 hazptr_owner<Node1> hptr0;
74 DEBUG_PRINT("=== hptr1");
75 hazptr_owner<Node1> hptr1(myDomain0);
76 DEBUG_PRINT("=== hptr2");
77 hazptr_owner<Node1> hptr2(myDomain1);
78 DEBUG_PRINT("=== hptr3");
79 hazptr_owner<Node1> hptr3;
83 Node1* n0 = shared0.load();
84 Node1* n1 = shared1.load();
85 Node1* n2 = shared2.load();
86 Node1* n3 = shared3.load();
88 if (hptr0.try_protect(n0, shared0)) {}
89 if (hptr1.try_protect(n1, shared1)) {}
92 if (hptr2.try_protect(n3, shared3)) {}
98 DEBUG_PRINT("=== retire n0 " << n0);
100 DEBUG_PRINT("=== retire n1 " << n1);
101 n1->retire(default_hazptr_domain());
102 DEBUG_PRINT("=== retire n2 " << n2);
103 n2->retire(myDomain0);
104 DEBUG_PRINT("=== retire n3 " << n3);
105 n3->retire(myDomain1);
108 TEST_F(HazptrTest, Test2) {
109 Node2* node0 = new Node2;
110 DEBUG_PRINT("=== new node0 " << node0 << " " << sizeof(*node0));
111 Node2* node1 = (Node2*)malloc(sizeof(Node2));
112 DEBUG_PRINT("=== malloc node1 " << node1 << " " << sizeof(*node1));
113 Node2* node2 = (Node2*)malloc(sizeof(Node2));
114 DEBUG_PRINT("=== malloc node2 " << node2 << " " << sizeof(*node2));
115 Node2* node3 = (Node2*)malloc(sizeof(Node2));
116 DEBUG_PRINT("=== malloc node3 " << node3 << " " << sizeof(*node3));
120 std::atomic<Node2*> shared0 = {node0};
121 std::atomic<Node2*> shared1 = {node1};
122 std::atomic<Node2*> shared2 = {node2};
123 std::atomic<Node2*> shared3 = {node3};
125 MineMemoryResource mineMr;
126 DEBUG_PRINT("=== mineMr " << &mineMr);
127 hazptr_domain mineDomain0;
128 DEBUG_PRINT("=== mineDomain0 " << &mineDomain0);
129 hazptr_domain mineDomain1(&mineMr);
130 DEBUG_PRINT("=== mineDomain1 " << &mineDomain1);
134 DEBUG_PRINT("=== hptr0");
135 hazptr_owner<Node2> hptr0;
136 DEBUG_PRINT("=== hptr1");
137 hazptr_owner<Node2> hptr1(mineDomain0);
138 DEBUG_PRINT("=== hptr2");
139 hazptr_owner<Node2> hptr2(mineDomain1);
140 DEBUG_PRINT("=== hptr3");
141 hazptr_owner<Node2> hptr3;
145 Node2* n0 = shared0.load();
146 Node2* n1 = shared1.load();
147 Node2* n2 = shared2.load();
148 Node2* n3 = shared3.load();
150 if (hptr0.try_protect(n0, shared0)) {}
151 if (hptr1.try_protect(n1, shared1)) {}
154 if (hptr2.try_protect(n3, shared3)) {}
160 DEBUG_PRINT("=== retire n0 " << n0);
161 n0->retire(default_hazptr_domain(), &mineReclaimFnDelete);
162 DEBUG_PRINT("=== retire n1 " << n1);
163 n1->retire(default_hazptr_domain(), &mineReclaimFnFree);
164 DEBUG_PRINT("=== retire n2 " << n2);
165 n2->retire(mineDomain0, &mineReclaimFnFree);
166 DEBUG_PRINT("=== retire n3 " << n3);
167 n3->retire(mineDomain1, &mineReclaimFnFree);
170 TEST_F(HazptrTest, LIFO) {
172 CHECK_GT(FLAGS_num_threads, 0);
173 for (int i = 0; i < FLAGS_num_reps; ++i) {
174 DEBUG_PRINT("========== start of rep scope");
176 std::vector<std::thread> threads(FLAGS_num_threads);
177 for (int tid = 0; tid < FLAGS_num_threads; ++tid) {
178 threads[tid] = std::thread([&s, tid]() {
179 for (int j = tid; j < FLAGS_num_ops; j += FLAGS_num_threads) {
182 while (!s.pop(res)) {}
186 for (auto& t : threads) {
189 DEBUG_PRINT("========== end of rep scope");
193 TEST_F(HazptrTest, SWMRLIST) {
195 hazptr_domain custom_domain;
197 CHECK_GT(FLAGS_num_threads, 0);
198 for (int i = 0; i < FLAGS_num_reps; ++i) {
199 DEBUG_PRINT("========== start of rep scope");
200 SWMRListSet<T> s(custom_domain);
201 std::vector<std::thread> threads(FLAGS_num_threads);
202 for (int tid = 0; tid < FLAGS_num_threads; ++tid) {
203 threads[tid] = std::thread([&s, tid]() {
204 for (int j = tid; j < FLAGS_num_ops; j += FLAGS_num_threads) {
209 for (int j = 0; j < 10; ++j) {
212 for (int j = 0; j < 10; ++j) {
215 for (auto& t : threads) {
218 DEBUG_PRINT("========== end of rep scope");
222 TEST_F(HazptrTest, WIDECAS) {
225 std::string v = "11112222";
226 auto ret = s.cas(u, v);
242 TEST_F(HazptrTest, VirtualTest) {
243 struct Thing : public hazptr_obj_base<Thing> {
245 DEBUG_PRINT("this: " << this << " &a: " << &a << " a: " << a);
249 for (int i = 0; i < 100; i++) {
250 auto bar = new Thing;
253 hazptr_owner<Thing> hptr;
256 EXPECT_EQ(bar->a, i);
260 TEST_F(HazptrTest, DestructionTest) {
261 hazptr_domain myDomain0;
262 struct Thing : public hazptr_obj_base<Thing> {
264 Thing(Thing* n) : next(n) {}
266 DEBUG_PRINT("this: " << this << " next: " << next);
272 Thing* last{nullptr};
273 for (int i = 0; i < 2000; i++) {
274 last = new Thing(last);