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