e119cde9c96401a264a1d736cfb7d0a313bd4c5c
[folly.git] / folly / test / AHMIntStressTest.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 <thread>
18 #include <memory>
19 #include <mutex>
20
21 #include <folly/AtomicHashMap.h>
22 #include <folly/ScopeGuard.h>
23 #include <folly/Memory.h>
24 #include <folly/portability/GTest.h>
25
26 namespace {
27
28 struct MyObject {
29   explicit MyObject(int i) : i(i) {}
30   int i;
31 };
32
33 typedef folly::AtomicHashMap<int,std::shared_ptr<MyObject>> MyMap;
34 typedef std::lock_guard<std::mutex> Guard;
35
36 std::unique_ptr<MyMap> newMap() { return std::make_unique<MyMap>(100); }
37
38 struct MyObjectDirectory {
39   MyObjectDirectory()
40     : cur_(newMap())
41     , prev_(newMap())
42   {}
43
44   std::shared_ptr<MyObject> get(int key) {
45     auto val = tryGet(key);
46     if (val) {
47       return val;
48     }
49
50     std::shared_ptr<MyMap> cur;
51     {
52       Guard g(lock_);
53       cur = cur_;
54     }
55
56     auto ret = cur->insert(key, std::make_shared<MyObject>(key));
57     return ret.first->second;
58   }
59
60   std::shared_ptr<MyObject> tryGet(int key) {
61     std::shared_ptr<MyMap> cur;
62     std::shared_ptr<MyMap> prev;
63     {
64       Guard g(lock_);
65       cur = cur_;
66       prev = prev_;
67     }
68
69     auto it = cur->find(key);
70     if (it != cur->end()) {
71       return it->second;
72     }
73
74     it = prev->find(key);
75     if (it != prev->end()) {
76       auto ret = cur->insert(key, it->second);
77       return ret.first->second;
78     }
79
80     return nullptr;
81   }
82
83   void archive() {
84     std::shared_ptr<MyMap> cur(newMap());
85
86     Guard g(lock_);
87     prev_ = cur_;
88     cur_ = cur;
89   }
90
91   std::mutex lock_;
92   std::shared_ptr<MyMap> cur_;
93   std::shared_ptr<MyMap> prev_;
94 };
95
96 }
97
98 //////////////////////////////////////////////////////////////////////
99
100 /*
101  * This test case stresses ThreadLocal allocation/deallocation heavily
102  * via ThreadCachedInt and AtomicHashMap, and a bunch of other
103  * mallocing.
104  */
105 TEST(AHMIntStressTest, Test) {
106   auto const objs = new MyObjectDirectory();
107   SCOPE_EXIT { delete objs; };
108
109   std::vector<std::thread> threads;
110   for (int threadId = 0; threadId < 64; ++threadId) {
111     threads.emplace_back([objs] {
112       for (int recycles = 0; recycles < 500; ++recycles) {
113         for (int i = 0; i < 10; i++) {
114           auto val = objs->get(i);
115         }
116
117         objs->archive();
118       }
119     });
120   }
121
122   for (auto& t : threads) t.join();
123 }