Uses cdsstress library
[junction.git] / test / junction_parallel_driver.cpp
1 #include <junction/ConcurrentMap_Crude.h>
2 #include <junction/ConcurrentMap_Grampa.h>
3 #include <junction/ConcurrentMap_Leapfrog.h>
4 #include <junction/ConcurrentMap_Linear.h>
5
6 #include <cds_test/stress_test.h>
7 #include <cds_test/stress_test_util.h>
8
9 #include <algorithm>
10 #include <iostream>
11 #include <memory>
12 #include <random>
13 #include <thread>
14
15 namespace junction_test {
16
17 class JunctionMapInsDelFindTest_Parallel : public cds_test::stress_fixture {
18 protected:
19   typedef junction::ConcurrentMap_Grampa<size_t, size_t> GrampaMap;
20   typedef junction::ConcurrentMap_Linear<size_t, size_t> LinearMap;
21   typedef junction::ConcurrentMap_Leapfrog<size_t, size_t> LeapfrogMap;
22   typedef junction::ConcurrentMap_Crude<size_t, size_t> CrudeMap;
23
24   static unsigned s_nInsertPercentage;
25   static unsigned s_nDeletePercentage;
26   static size_t s_nGCFrequency; // Run GC after "s_nGCFrequency" operations.
27   static size_t s_nThreadCount;
28   static size_t s_nMapKeyRange;
29   static size_t s_nCrudeMapCapacity;
30
31   enum actions { do_find, do_insert, do_delete };
32   static const unsigned int kShuffleSize = 100;
33   static actions s_arrShuffle[kShuffleSize];
34
35   static size_t s_nCrudePassCount;
36   static size_t s_nGrampaPassCount;
37   static size_t s_nLinearPassCount;
38   static size_t s_nLeapfrogPassCount;
39
40   static void InitShuffleArray() {
41     // Build an array of shuffled actions.
42     EXPECT_LE(s_nInsertPercentage + s_nDeletePercentage, 100);
43     actions* pFirst = s_arrShuffle;
44     actions* pLast = s_arrShuffle + s_nInsertPercentage;
45     std::fill(pFirst, pLast, do_insert);
46     pFirst = pLast;
47     pLast += s_nDeletePercentage;
48     std::fill(pFirst, pLast, do_delete);
49     pFirst = pLast;
50     pLast = s_arrShuffle + sizeof(s_arrShuffle) / sizeof(s_arrShuffle[0]);
51     if (pFirst < pLast) {
52       std::fill(pFirst, pLast, do_find);
53     }
54     std::random_device rd;
55     std::mt19937 g(rd());
56     std::shuffle(s_arrShuffle, pLast, g);
57   }
58
59   static void SetUpTestCase() {
60     InitShuffleArray();
61     const cds_test::config& cfg = get_config("ParallelJunction");
62     GetConfigNonZeroExpected(InsertPercentage, 5);
63     GetConfigNonZeroExpected(DeletePercentage, 5);
64     GetConfigNonZeroExpected(ThreadCount, 4);
65     GetConfigNonZeroExpected(MapKeyRange, 20000);
66     GetConfigNonZeroExpected(CrudeMapCapacity, s_nMapKeyRange * 64);
67     GetConfigNonZeroExpected(GCFrequency, 1500);
68     GetConfigNonZeroExpected(CrudePassCount, 1500000000);
69     GetConfigNonZeroExpected(GrampaPassCount, 650000000);
70     GetConfigNonZeroExpected(LinearPassCount, 900000000);
71     GetConfigNonZeroExpected(LeapfrogPassCount, 850000000);
72   }
73
74   template <typename Map, typename Key, typename Value>
75   static bool map_insert(Map* map, Key key, Value value) {
76     auto iter = map->insertOrFind(key);
77     if (!iter.getValue() || iter.getValue() != value) {
78       // Insert/update the <key,value> pair
79       iter.assignValue(value);
80       return true;
81     } else {
82       return false;
83     }
84   }
85
86   template <typename Map, typename Key>
87   static bool map_delete(Map* map, Key key) {
88     auto iter = map->find(key);
89     if (iter.getValue()) {
90       iter.eraseValue();
91       return true;
92     } else {
93       return false;
94     }
95   }
96
97   template <typename Map, typename Key>
98   static bool map_find(Map* map, Key key) {
99     auto iter = map->find(key);
100     if (iter.getValue()) {
101       return true;
102     } else {
103       return false;
104     }
105   }
106
107   // Specialization for CrudeMap
108   template <typename Key, typename Value>
109   static bool map_insert(CrudeMap* map, Key key, Value value) {
110     auto old_val = map->get(key);
111     if (!old_val || old_val != value) {
112       map->assign(key, value);
113       return true;
114     } else {
115       return false;
116     }
117   }
118
119   template <typename Key> static bool map_delete(CrudeMap* map, Key key) {
120     if (!map->get(key)) {
121       map->assign(key, ((Key)0));
122       return true;
123     } else {
124       return false;
125     }
126   }
127
128   template <typename Key> static bool map_find(CrudeMap* map, Key key) {
129     return map->get(key) != ((Key)0);
130   }
131
132   template <typename Map> static void run_test(Map* map, size_t pass_count) {
133     auto qsbrContext = junction::DefaultQSBR.createContext();
134
135     std::random_device rd;
136     std::mt19937 gen(rd());
137     std::uniform_int_distribution<size_t> dis(2, s_nMapKeyRange);
138
139     unsigned action_index = 0;
140     size_t nInsertedNum = 0;
141     size_t nFindSuccess = 0;
142     size_t nOperations = 0;
143
144     for (size_t count = 0; count < pass_count; count++) {
145       // The number to operate on the map.
146       size_t key = dis(gen);
147       switch (s_arrShuffle[action_index]) {
148         case do_insert: {
149           size_t val = dis(gen);
150           if (map_insert(map, key, val)) {
151             nInsertedNum++;
152           }
153           break;
154         }
155         case do_delete: {
156           map_delete(map, key);
157           break;
158         }
159         case do_find: {
160           if (map_find(map, key)) {
161             ++nFindSuccess;
162           }
163           break;
164         }
165         default: { break; }
166       }
167       if (++action_index >= kShuffleSize) {
168         action_index = 0;
169       }
170       if (++nOperations > s_nGCFrequency) {
171         junction::DefaultQSBR.update(qsbrContext);
172         nOperations = 0;
173       }
174     }
175     junction::DefaultQSBR.update(qsbrContext);
176     junction::DefaultQSBR.destroyContext(qsbrContext);
177   }
178 };
179
180 size_t JunctionMapInsDelFindTest_Parallel::s_nThreadCount;
181 size_t JunctionMapInsDelFindTest_Parallel::s_nMapKeyRange;
182 size_t JunctionMapInsDelFindTest_Parallel::s_nCrudeMapCapacity;
183 size_t JunctionMapInsDelFindTest_Parallel::s_nGCFrequency;
184 unsigned JunctionMapInsDelFindTest_Parallel::s_nInsertPercentage;
185 unsigned JunctionMapInsDelFindTest_Parallel::s_nDeletePercentage;
186 const unsigned int JunctionMapInsDelFindTest_Parallel::kShuffleSize;
187 JunctionMapInsDelFindTest_Parallel::actions JunctionMapInsDelFindTest_Parallel::
188     s_arrShuffle[JunctionMapInsDelFindTest_Parallel::kShuffleSize];
189 size_t JunctionMapInsDelFindTest_Parallel::s_nCrudePassCount;
190 size_t JunctionMapInsDelFindTest_Parallel::s_nGrampaPassCount;
191 size_t JunctionMapInsDelFindTest_Parallel::s_nLinearPassCount;
192 size_t JunctionMapInsDelFindTest_Parallel::s_nLeapfrogPassCount;
193
194 #define JunctionThreading(map_type, pass_count)                                \
195   std::unique_ptr<std::thread[]> threads(new std::thread[s_nThreadCount]);       \
196   for (size_t i = 0; i < s_nThreadCount; i++) {                                  \
197     threads[i] = std::thread(run_test<map_type>, map.get(), pass_count);       \
198   }                                                                            \
199   for (size_t i = 0; i < s_nThreadCount; i++) {                                  \
200     threads[i].join();                                                         \
201   }
202
203 TEST_F(JunctionMapInsDelFindTest_Parallel, JunctionMapCrude) {
204   std::unique_ptr<CrudeMap> map(new CrudeMap(s_nCrudeMapCapacity));
205   JunctionThreading(CrudeMap, s_nCrudePassCount);
206 }
207
208 TEST_F(JunctionMapInsDelFindTest_Parallel, JunctionMapLeapfrog) {
209   std::unique_ptr<LeapfrogMap> map(new LeapfrogMap());
210   JunctionThreading(LeapfrogMap, s_nLeapfrogPassCount);
211 }
212
213 TEST_F(JunctionMapInsDelFindTest_Parallel, JunctionMapLinear) {
214   std::unique_ptr<LinearMap> map(new LinearMap());
215   JunctionThreading(LinearMap, s_nLinearPassCount);
216 }
217
218 TEST_F(JunctionMapInsDelFindTest_Parallel, JunctionMapGrampa) {
219   std::unique_ptr<GrampaMap> map(new GrampaMap());
220   JunctionThreading(GrampaMap, s_nGrampaPassCount);
221 }
222
223 } // namespace junction_test
224
225 int main(int argc, char** argv) {
226   // Read test config file
227   cds_test::init_config(argc, argv);
228
229   // Init Google test
230   ::testing::InitGoogleTest(&argc, argv);
231   int result = RUN_ALL_TESTS();
232   return result;
233 }