• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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