1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "file.h"
17 #include "panda_cache.h"
18
19 #include <gtest/gtest.h>
20 #include <thread>
21
22 namespace panda {
23
24 class Method;
25 class Field;
26 class Class;
27
28 namespace panda_file::test {
29
30 using EntityId = File::EntityId;
31
GetNewMockPointer()32 static void *GetNewMockPointer()
33 {
34 static int id = 1;
35 return reinterpret_cast<void *>(id++);
36 }
TEST(PandaCache,TestMethodCache)37 TEST(PandaCache, TestMethodCache)
38 {
39 PandaCache cache;
40 EntityId id1(100);
41 ASSERT_EQ(cache.GetMethodFromCache(id1), nullptr);
42
43 auto *method1 = reinterpret_cast<Method *>(GetNewMockPointer());
44 cache.SetMethodCache(id1, method1);
45 ASSERT_EQ(cache.GetMethodFromCache(id1), method1);
46
47 EntityId id2(10000);
48 auto *method2 = reinterpret_cast<Method *>(GetNewMockPointer());
49 cache.SetMethodCache(id2, method2);
50 ASSERT_EQ(cache.GetMethodFromCache(id2), method2);
51 }
52
TEST(PandaCache,TestFieldCache)53 TEST(PandaCache, TestFieldCache)
54 {
55 PandaCache cache;
56 EntityId id1(100);
57 // TODO(yxr) : make sure no conflicts
58 EntityId new_id1(id1.GetOffset() << 2U);
59 ASSERT_EQ(cache.GetFieldFromCache(new_id1), nullptr);
60
61 auto *field1 = reinterpret_cast<Field *>(GetNewMockPointer());
62 cache.SetFieldCache(new_id1, field1);
63 ASSERT_EQ(cache.GetFieldFromCache(new_id1), field1);
64
65 EntityId id2(10000);
66 // TODO(yxr) : make sure no conflicts
67 EntityId new_id2(id2.GetOffset() << 2U);
68 auto *field2 = reinterpret_cast<Field *>(GetNewMockPointer());
69 cache.SetFieldCache(new_id2, field2);
70 ASSERT_EQ(cache.GetFieldFromCache(new_id2), field2);
71 }
72
TEST(PandaCache,TestClassCache)73 TEST(PandaCache, TestClassCache)
74 {
75 PandaCache cache;
76 EntityId id1(100);
77 ASSERT_EQ(cache.GetClassFromCache(id1), nullptr);
78
79 auto *class1 = reinterpret_cast<Class *>(GetNewMockPointer());
80 cache.SetClassCache(id1, class1);
81 ASSERT_EQ(cache.GetClassFromCache(id1), class1);
82
83 EntityId id2(10000);
84 auto *class2 = reinterpret_cast<Class *>(GetNewMockPointer());
85 cache.SetClassCache(id2, class2);
86 ASSERT_EQ(cache.GetClassFromCache(id2), class2);
87 }
88
89 struct ElementMock {
90 int data;
91 };
92
GetNewMockElement(int i)93 static ElementMock *GetNewMockElement(int i)
94 {
95 auto *m = new ElementMock();
96 m->data = i;
97 return m;
98 }
99
100 static const int NUMBER_OF_READERS = 4;
101 static const int NUMBER_OF_ELEMENTS = 4;
102
103 class CacheOps {
104 public:
CacheOps(PandaCache * cache)105 explicit CacheOps(PandaCache *cache) : cache_(cache) {}
106
runWriter()107 void runWriter()
108 {
109 for (int i = 0; i < NUMBER_OF_ELEMENTS; i++) {
110 EntityId id(i);
111 auto *m = GetNewMockElement(i);
112 SetElement(id, m);
113 ASSERT_EQ(GetElement(id), m);
114 }
115 }
116
RunReader()117 void RunReader()
118 {
119 for (int i = 0; i < NUMBER_OF_ELEMENTS; i++) {
120 EntityId id(i);
121 auto *m = GetElement(id);
122 while (m == nullptr) {
123 m = GetElement(id);
124 }
125 int d = m->data;
126 ASSERT_EQ(d, i);
127 }
128 }
129
130 protected:
131 PandaCache *cache_;
132 virtual ElementMock *GetElement(EntityId id) = 0;
133 virtual void SetElement(EntityId id, ElementMock *m) = 0;
134 };
135
136 class MethodCacheOps : public CacheOps {
137 public:
MethodCacheOps(PandaCache * cache)138 explicit MethodCacheOps(PandaCache *cache) : CacheOps(cache) {}
139
140 protected:
GetElement(EntityId id)141 ElementMock *GetElement(EntityId id) override
142 {
143 Method *f = cache_->GetMethodFromCache(id);
144 if (f == nullptr) {
145 return nullptr;
146 }
147 return reinterpret_cast<ElementMock *>(f);
148 }
149
SetElement(EntityId id,ElementMock * m)150 void SetElement(EntityId id, ElementMock *m) override
151 {
152 auto *f = reinterpret_cast<Method *>(m);
153 cache_->SetMethodCache(id, f);
154 }
155 };
156
157 class FieldCacheOps : public CacheOps {
158 public:
FieldCacheOps(PandaCache * cache)159 explicit FieldCacheOps(PandaCache *cache) : CacheOps(cache) {}
160
161 protected:
GetElement(EntityId id)162 ElementMock *GetElement(EntityId id) override
163 {
164 // TODO(yxr) : make sure no conflicts
165 // CacheOps.RunReader expect no conflicts
166 EntityId new_id(id.GetOffset() << 2U);
167 Field *f = cache_->GetFieldFromCache(new_id);
168 if (f == nullptr) {
169 return nullptr;
170 }
171 return reinterpret_cast<ElementMock *>(f);
172 }
173
SetElement(EntityId id,ElementMock * m)174 void SetElement(EntityId id, ElementMock *m) override
175 {
176 // TODO(yxr) : make sure no conflicts
177 // CacheOps.RunReader expect no conflicts
178 EntityId new_id(id.GetOffset() << 2U);
179 auto *f = reinterpret_cast<Field *>(m);
180 cache_->SetFieldCache(new_id, f);
181 }
182 };
183
184 class ClassCacheOps : public CacheOps {
185 public:
ClassCacheOps(PandaCache * cache)186 explicit ClassCacheOps(PandaCache *cache) : CacheOps(cache) {}
187
188 protected:
GetElement(EntityId id)189 ElementMock *GetElement(EntityId id) override
190 {
191 Class *cl = cache_->GetClassFromCache(id);
192 if (cl == nullptr) {
193 return nullptr;
194 }
195 return reinterpret_cast<ElementMock *>(cl);
196 }
197
SetElement(EntityId id,ElementMock * m)198 void SetElement(EntityId id, ElementMock *m) override
199 {
200 auto *cl = reinterpret_cast<Class *>(m);
201 cache_->SetClassCache(id, cl);
202 }
203 };
204
MethodWriterThread(PandaCache * cache)205 void MethodWriterThread(PandaCache *cache)
206 {
207 MethodCacheOps ops(cache);
208 ops.runWriter();
209 }
210
MethodReaderThread(PandaCache * cache)211 void MethodReaderThread(PandaCache *cache)
212 {
213 MethodCacheOps ops(cache);
214 ops.RunReader();
215 }
216
FieldWriterThread(PandaCache * cache)217 void FieldWriterThread(PandaCache *cache)
218 {
219 FieldCacheOps ops(cache);
220 ops.runWriter();
221 }
222
FieldReaderThread(PandaCache * cache)223 void FieldReaderThread(PandaCache *cache)
224 {
225 FieldCacheOps ops(cache);
226 ops.RunReader();
227 }
228
ClassWriterThread(PandaCache * cache)229 void ClassWriterThread(PandaCache *cache)
230 {
231 ClassCacheOps ops(cache);
232 ops.runWriter();
233 }
234
ClassReaderThread(PandaCache * cache)235 void ClassReaderThread(PandaCache *cache)
236 {
237 ClassCacheOps ops(cache);
238 ops.RunReader();
239 }
240
CleanMethodMocks(const PandaCache * cache)241 void CleanMethodMocks(const PandaCache *cache)
242 {
243 for (int i = 0; i < NUMBER_OF_ELEMENTS; i++) {
244 EntityId id(i);
245 auto *m = reinterpret_cast<ElementMock *>(cache->GetMethodFromCache(id));
246 delete m;
247 }
248 }
249
CleanFieldMocks(const PandaCache * cache)250 void CleanFieldMocks(const PandaCache *cache)
251 {
252 for (int i = 0; i < NUMBER_OF_ELEMENTS; i++) {
253 EntityId id(i);
254 // TODO(yxr) : make sure no conflicts
255 EntityId new_id(id.GetOffset() << 2U);
256 auto *m = reinterpret_cast<ElementMock *>(cache->GetFieldFromCache(new_id));
257 delete m;
258 }
259 }
260
CleanClassMocks(const PandaCache * cache)261 void CleanClassMocks(const PandaCache *cache)
262 {
263 for (int i = 0; i < NUMBER_OF_ELEMENTS; i++) {
264 EntityId id(i);
265 auto *m = reinterpret_cast<ElementMock *>(cache->GetClassFromCache(id));
266 delete m;
267 }
268 }
269
TEST(PandaCache,TestManyThreadsMethodCache)270 TEST(PandaCache, TestManyThreadsMethodCache)
271 {
272 PandaCache cache;
273
274 std::thread threads[NUMBER_OF_READERS];
275 auto writer = std::thread(MethodWriterThread, &cache);
276 for (int i = 0; i < NUMBER_OF_READERS; i++) {
277 threads[i] = std::thread(MethodReaderThread, &cache);
278 }
279 for (int i = 0; i < NUMBER_OF_READERS; i++) {
280 threads[i].join();
281 }
282 writer.join();
283 CleanMethodMocks(&cache);
284 }
285
TEST(PandaCache,TestManyThreadsFieldCache)286 TEST(PandaCache, TestManyThreadsFieldCache)
287 {
288 PandaCache cache;
289
290 std::thread threads[NUMBER_OF_READERS];
291 auto writer = std::thread(FieldWriterThread, &cache);
292 for (int i = 0; i < NUMBER_OF_READERS; i++) {
293 threads[i] = std::thread(FieldReaderThread, &cache);
294 }
295 for (int i = 0; i < NUMBER_OF_READERS; i++) {
296 threads[i].join();
297 }
298 writer.join();
299 CleanFieldMocks(&cache);
300 }
301
TEST(PandaCache,TestManyThreadsClassCache)302 TEST(PandaCache, TestManyThreadsClassCache)
303 {
304 PandaCache cache;
305
306 std::thread threads[NUMBER_OF_READERS];
307 auto writer = std::thread(ClassWriterThread, &cache);
308 for (int i = 0; i < NUMBER_OF_READERS; i++) {
309 threads[i] = std::thread(ClassReaderThread, &cache);
310 }
311 for (int i = 0; i < NUMBER_OF_READERS; i++) {
312 threads[i].join();
313 }
314 writer.join();
315 CleanClassMocks(&cache);
316 }
317
318 } // namespace panda_file::test
319 } // namespace panda
320