• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 <cstdio>
17 #include <thread>
18 #include <memory> /* unique_ptr */
19 #include <cstring>
20 #include "gtest/gtest.h"
21 #include "purgeable_mem.h"
22 
23 namespace OHOS {
24 namespace PurgeableMem {
25 using namespace testing;
26 using namespace testing::ext;
27 
28 static constexpr int PRINT_INTERVAL_SECONDS = 1;
29 static constexpr int RECLAIM_INTERVAL_SECONDS = 1;
30 static constexpr int MODIFY_INTERVAL_SECONDS = 2;
31 void LoopPrintAlphabet(PurgeableMem *pdata, unsigned int loopCount);
32 bool ReclaimPurgeable(void);
33 void LoopReclaimPurgeable(unsigned int loopCount);
34 void ModifyPurgMemByBuilder(PurgeableMem *pdata, std::unique_ptr<PurgeableMemBuilder> mod);
35 
36 class TestDataBuilder : public PurgeableMemBuilder {
37 public:
TestDataBuilder(char start,char end)38     TestDataBuilder(char start, char end)
39     {
40         this->start = start;
41         this->end = end;
42     }
43 
Build(void * data,size_t size)44     bool Build(void *data, size_t size)
45     {
46         if (size <= 0) {
47             return true;
48         }
49         char *str = static_cast<char *>(data);
50         size_t len = 0;
51         for (char ch = start; ch <= end && len < size; ch++) {
52             str[len++] = ch;
53         }
54         str[size - 1] = 0;
55         std::cout << "rebuild addr("<< (unsigned long long)str <<") " <<
56             start << "~" << end << ", data=[" << str << "]" << std::endl;
57         return true;
58     }
59 
~TestDataBuilder()60     ~TestDataBuilder()
61     {
62         std::cout << "~TestDataBuilder" << std::endl;
63     }
64 
65 private:
66     char start, end;
67 };
68 
69 class TestDataModifier : public PurgeableMemBuilder {
70 public:
TestDataModifier(char from,char to)71     TestDataModifier(char from, char to)
72     {
73         this->from = from;
74         this->to = to;
75     }
76 
Build(void * data,size_t size)77     bool Build(void *data, size_t size)
78     {
79         char *str = static_cast<char *>(data);
80         for (size_t i = 0; i < size && str[i]; i++) {
81             if (str[i] == from) {
82                 str[i] = to;
83             }
84         }
85         return true;
86     }
87 
~TestDataModifier()88     ~TestDataModifier()
89     {
90         std::cout << "~TestDataModifier" << std::endl;
91     }
92 
93 private:
94     char from, to;
95 };
96 
97 class TestBigDataBuilder : public PurgeableMemBuilder {
98 public:
TestBigDataBuilder(char target)99     explicit TestBigDataBuilder(char target)
100     {
101         this->target = target;
102     }
103 
Build(void * data,size_t size)104     bool Build(void *data, size_t size)
105     {
106         if (size <= 0) {
107             return true;
108         }
109         char *str = static_cast<char *>(data);
110         size_t len = 0;
111         for (char ch = target; len < size;) {
112             str[len++] = ch;
113         }
114         str[size - 1] = 0;
115         return true;
116     }
117 
~TestBigDataBuilder()118     ~TestBigDataBuilder()
119     {
120         std::cout << "~TestBigDataBuilder" << std::endl;
121     }
122 
123 private:
124     char target;
125 };
126 
127 class PurgeableCppTest : public testing::Test {
128 public:
129     static void SetUpTestCase();
130     static void TearDownTestCase();
131     void SetUp();
132     void TearDown();
133 };
134 
SetUpTestCase()135 void PurgeableCppTest::SetUpTestCase()
136 {
137 }
138 
TearDownTestCase()139 void PurgeableCppTest::TearDownTestCase()
140 {
141 }
142 
SetUp()143 void PurgeableCppTest::SetUp()
144 {
145 }
146 
TearDown()147 void PurgeableCppTest::TearDown()
148 {
149 }
150 
151 HWTEST_F(PurgeableCppTest, MultiObjCreateTest, TestSize.Level1)
152 {
153     const char alphabetFinal[] = "BBCDEFGHIJKLMNOPQRSTUVWXYZ\0";
154     std::unique_ptr<PurgeableMemBuilder> builder1 = std::make_unique<TestDataBuilder>('A', 'Z');
155     std::unique_ptr<PurgeableMemBuilder> builder2 = std::make_unique<TestDataBuilder>('A', 'Z');
156     std::unique_ptr<PurgeableMemBuilder> mod1 = std::make_unique<TestDataModifier>('A', 'B');
157     std::unique_ptr<PurgeableMemBuilder> mod2 = std::make_unique<TestDataModifier>('A', 'B');
158 
159     PurgeableMem pobj1(27, std::move(builder1));
160     LoopPrintAlphabet(&pobj1, 1);
161     ModifyPurgMemByBuilder(&pobj1, std::move(mod1));
162     LoopPrintAlphabet(&pobj1, 1);
163     LoopReclaimPurgeable(1);
164 
165     PurgeableMem pobj2(27, std::move(builder2));
166     LoopPrintAlphabet(&pobj2, 1);
167     ModifyPurgMemByBuilder(&pobj2, std::move(mod2));
168     LoopPrintAlphabet(&pobj2, 1);
169     LoopReclaimPurgeable(1);
170 
171     int ret1 = 1;
172     int ret2 = 1;
173     int times1 = 0;
174     int times2 = 0;
175     while (times1++ < 10) {
176         if (pobj1.BeginRead()) {
177             ret1 = strncmp(alphabetFinal, static_cast<char *>(pobj1.GetContent()), 26);
178             pobj1.EndRead();
179             break;
180         } else {
181             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
182         }
183     }
184 
185     while (times2++ < 10) {
186         if (pobj2.BeginRead()) {
187             ret2 = strncmp(alphabetFinal, static_cast<char *>(pobj2.GetContent()), 26);
188             pobj2.EndRead();
189             break;
190         } else {
191             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
192         }
193     }
194 
195     EXPECT_EQ(ret1, 0);
196     EXPECT_EQ(ret2, 0);
197 }
198 
199 HWTEST_F(PurgeableCppTest, ReadTest, TestSize.Level1)
200 {
201     const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\0";
202     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
203     PurgeableMem *pobj = new PurgeableMem(27, std::move(builder));
204     LoopReclaimPurgeable(1);
205 
206     int times = 0;
207     int ret = 1;
208     while (times++ < 10) {
209         if (pobj->BeginRead()) {
210             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), 26);
211             pobj->EndRead();
212             break;
213         } else {
214             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
215         }
216     }
217     delete pobj;
218     pobj = nullptr;
219     EXPECT_EQ(ret, 0);
220 }
221 
222 HWTEST_F(PurgeableCppTest, WriteTest, TestSize.Level1)
223 {
224     const char alphabet[] = "CCCDEFGHIJKLMNOPQRSTUVWXYZ\0";
225     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
226     PurgeableMem *pobj = new PurgeableMem(27, std::move(builder));
227     LoopReclaimPurgeable(1);
228 
229     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
230     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
231     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
232     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
233 
234     int times = 0;
235     int ret = 1;
236     while (times++ < 10) {
237         if (pobj->BeginRead()) {
238             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), 26);
239             pobj->EndRead();
240             break;
241         } else {
242             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
243         }
244     }
245     delete pobj;
246     pobj = nullptr;
247     EXPECT_EQ(ret, 0);
248 }
249 
250 HWTEST_F(PurgeableCppTest, ReadWriteTest, TestSize.Level1)
251 {
252     const char alphabet[] = "DDDDEFGHIJKLMNOPQRSTUVWXYZ\0";
253     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
254     PurgeableMem *pobj = new PurgeableMem(27, std::move(builder));
255 
256     LoopReclaimPurgeable(1);
257     LoopPrintAlphabet(pobj, 1);
258 
259     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
260     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
261     std::unique_ptr<PurgeableMemBuilder> modC2D = std::make_unique<TestDataModifier>('C', 'D');
262     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
263     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
264     ModifyPurgMemByBuilder(pobj, std::move(modC2D));
265 
266     int times = 0;
267     int ret = 1;
268     while (times++ < 10) {
269         if (pobj->BeginRead()) {
270             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), 26);
271             pobj->EndRead();
272             break;
273         } else {
274             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
275         }
276     }
277     delete pobj;
278     pobj = nullptr;
279     EXPECT_EQ(ret, 0);
280 }
281 
282 HWTEST_F(PurgeableCppTest, MutiPageReadTest, TestSize.Level1)
283 {
284     char alphabet[4098];
285     size_t len = 0;
286     for (char ch = 'A'; len < 4098;) {
287         alphabet[len++] = ch;
288     }
289     alphabet[4097] = 0;
290     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestBigDataBuilder>('A');
291     PurgeableMem *pobj = new PurgeableMem(4098, std::move(builder));
292 
293     LoopReclaimPurgeable(1);
294 
295     int times = 0;
296     int ret = 1;
297     while (times++ < 10) {
298         if (pobj->BeginRead()) {
299             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), 4097);
300             pobj->EndRead();
301             break;
302         } else {
303             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
304         }
305     }
306     delete pobj;
307     pobj = nullptr;
308     EXPECT_EQ(ret, 0);
309 }
310 
311 HWTEST_F(PurgeableCppTest, MutiPageWriteTest, TestSize.Level1)
312 {
313     char alphabet[4098];
314     size_t len = 0;
315     for (char ch = 'C'; len < 4098;) {
316         alphabet[len++] = ch;
317     }
318     alphabet[4097] = 0;
319     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestBigDataBuilder>('A');
320     PurgeableMem *pobj = new PurgeableMem(4098, std::move(builder));
321 
322     LoopReclaimPurgeable(1);
323 
324     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
325     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
326     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
327     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
328 
329     int times = 0;
330     int ret = 1;
331     while (times++ < 10) {
332         if (pobj->BeginRead()) {
333             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), 4097);
334             pobj->EndRead();
335             break;
336         } else {
337             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
338         }
339     }
340     delete pobj;
341     pobj = nullptr;
342     EXPECT_EQ(ret, 0);
343 }
344 
345 HWTEST_F(PurgeableCppTest, MutiPageReadWriteTest, TestSize.Level1)
346 {
347     char alphabet[4098];
348     size_t len = 0;
349     for (char ch = 'D'; len < 4098;) {
350         alphabet[len++] = ch;
351     }
352     alphabet[4097] = 0;
353     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestBigDataBuilder>('A');
354     PurgeableMem *pobj = new PurgeableMem(4098, std::move(builder));
355     LoopReclaimPurgeable(1);
356     LoopPrintAlphabet(pobj, 1);
357 
358     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
359     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
360     std::unique_ptr<PurgeableMemBuilder> modC2D = std::make_unique<TestDataModifier>('C', 'D');
361     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
362     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
363     ModifyPurgMemByBuilder(pobj, std::move(modC2D));
364 
365     int times = 0;
366     int ret = 1;
367     while (times++ < 10) {
368         if (pobj->BeginRead()) {
369             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), 4097);
370             pobj->EndRead();
371             break;
372         } else {
373             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
374         }
375     }
376     delete pobj;
377     pobj = nullptr;
378     EXPECT_EQ(ret, 0);
379 }
380 
381 HWTEST_F(PurgeableCppTest, MutiMorePageReadWriteTest, TestSize.Level1)
382 {
383     size_t size = 5 * 1024 * 1024;
384     char *alphabet = (char *)malloc(size);
385     size_t len = 0;
386     for (char ch = 'D'; len < size;) {
387         alphabet[len++] = ch;
388     }
389     alphabet[size - 1] = 0;
390     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestBigDataBuilder>('A');
391     PurgeableMem *pobj = new PurgeableMem(size, std::move(builder));
392 
393     LoopReclaimPurgeable(1);
394     LoopPrintAlphabet(pobj, 1);
395 
396     std::unique_ptr<PurgeableMemBuilder> modA2B = std::make_unique<TestDataModifier>('A', 'B');
397     std::unique_ptr<PurgeableMemBuilder> modB2C = std::make_unique<TestDataModifier>('B', 'C');
398     std::unique_ptr<PurgeableMemBuilder> modC2D = std::make_unique<TestDataModifier>('C', 'D');
399     ModifyPurgMemByBuilder(pobj, std::move(modA2B));
400     ModifyPurgMemByBuilder(pobj, std::move(modB2C));
401     ModifyPurgMemByBuilder(pobj, std::move(modC2D));
402 
403     int times = 0;
404     int ret = 1;
405     while (times++ < 10) {
406         if (pobj->BeginRead()) {
407             ret = strncmp(alphabet, static_cast<char *>(pobj->GetContent()), size - 1);
408             pobj->EndRead();
409             break;
410         } else {
411             std::cout << __func__ << ": ERROR! BeginRead failed." << std::endl;
412         }
413     }
414     delete pobj;
415     pobj = nullptr;
416     free(alphabet);
417     alphabet = nullptr;
418     EXPECT_EQ(ret, 0);
419 }
420 
421 HWTEST_F(PurgeableCppTest, InvalidInputSizeTest, TestSize.Level1)
422 {
423     std::unique_ptr<PurgeableMemBuilder> builder = std::make_unique<TestDataBuilder>('A', 'Z');
424     PurgeableMem *pobj = new PurgeableMem(0, std::move(builder));
425     LoopReclaimPurgeable(1);
426     bool ret = pobj->BeginRead();
427     if (ret) {
428         pobj->EndRead();
429     }
430     delete pobj;
431     pobj = nullptr;
432     EXPECT_EQ(ret, false);
433 }
434 
435 HWTEST_F(PurgeableCppTest, InvalidInputBuilderTest, TestSize.Level1)
436 {
437     PurgeableMem *pobj = new PurgeableMem(27, nullptr);
438     LoopReclaimPurgeable(1);
439     bool ret = pobj->BeginRead();
440     if (ret) {
441         pobj->EndRead();
442     }
443     delete pobj;
444     pobj = nullptr;
445     EXPECT_EQ(ret, false);
446 }
447 
LoopPrintAlphabet(PurgeableMem * pdata,unsigned int loopCount)448 void LoopPrintAlphabet(PurgeableMem *pdata, unsigned int loopCount)
449 {
450     std::cout << "inter " << __func__ << std::endl;
451     for (unsigned int i = 0; i < loopCount; i++) {
452         if (!pdata->BeginRead()) {
453             std::cout << __func__ << ": " << i << ". ERROR! BeginRead failed." << std::endl;
454             break;
455         }
456         pdata->EndRead();
457         std::this_thread::sleep_for(std::chrono::seconds(PRINT_INTERVAL_SECONDS));
458     }
459     std::cout << "quit " << __func__ << std::endl;
460 }
461 
ReclaimPurgeable(void)462 bool ReclaimPurgeable(void)
463 {
464     FILE *f = fopen("/proc/sys/kernel/purgeable", "w");
465     if (!f) {
466         std::cout << __func__ << ": kernel not support" << std::endl;
467         return false;
468     }
469     bool succ = true;
470     if (fputs("1", f) == EOF) {
471         succ = false;
472     }
473 
474     if (fclose(f) == EOF) {
475         std::cout << __func__ << ": close file failed" << std::endl;
476     }
477 
478     return succ;
479 }
480 
LoopReclaimPurgeable(unsigned int loopCount)481 void LoopReclaimPurgeable(unsigned int loopCount)
482 {
483     bool ret = false;
484     std::cout << "inter " << __func__ << std::endl;
485     for (unsigned int i = 0; i < loopCount; i++) {
486         ret = ReclaimPurgeable();
487         std::cout << __func__ << ": " << i << ". Reclaim result=" << (ret ? "succ" : "fail") << std::endl;
488         std::this_thread::sleep_for(std::chrono::seconds(RECLAIM_INTERVAL_SECONDS)); /* wait reclaim finish */
489     }
490     std::cout << "quit " << __func__ << std::endl;
491 }
492 
ModifyPurgMemByBuilder(PurgeableMem * pdata,std::unique_ptr<PurgeableMemBuilder> mod)493 void ModifyPurgMemByBuilder(PurgeableMem *pdata, std::unique_ptr<PurgeableMemBuilder> mod)
494 {
495     if (!pdata->BeginWrite()) {
496         std::cout << __func__ << ": ERROR! BeginWrite failed." << std::endl;
497         return;
498     }
499     std::this_thread::sleep_for(std::chrono::seconds(MODIFY_INTERVAL_SECONDS));
500     pdata->ModifyContentByBuilder(std::move(mod));
501     pdata->EndWrite();
502 }
503 } /* namespace PurgeableMem */
504 } /* namespace OHOS */
505