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 23namespace OHOS { 24namespace PurgeableMem { 25using namespace testing; 26using namespace testing::ext; 27 28static constexpr int PRINT_INTERVAL_SECONDS = 1; 29static constexpr int RECLAIM_INTERVAL_SECONDS = 1; 30static constexpr int MODIFY_INTERVAL_SECONDS = 2; 31void LoopPrintAlphabet(PurgeableMem *pdata, unsigned int loopCount); 32bool ReclaimPurgeable(void); 33void LoopReclaimPurgeable(unsigned int loopCount); 34void ModifyPurgMemByBuilder(PurgeableMem *pdata, std::unique_ptr<PurgeableMemBuilder> mod); 35 36class TestDataBuilder : public PurgeableMemBuilder { 37public: 38 TestDataBuilder(char start, char end) 39 { 40 this->start = start; 41 this->end = end; 42 } 43 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 60 ~TestDataBuilder() 61 { 62 std::cout << "~TestDataBuilder" << std::endl; 63 } 64 65private: 66 char start, end; 67}; 68 69class TestDataModifier : public PurgeableMemBuilder { 70public: 71 TestDataModifier(char from, char to) 72 { 73 this->from = from; 74 this->to = to; 75 } 76 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 88 ~TestDataModifier() 89 { 90 std::cout << "~TestDataModifier" << std::endl; 91 } 92 93private: 94 char from, to; 95}; 96 97class TestBigDataBuilder : public PurgeableMemBuilder { 98public: 99 explicit TestBigDataBuilder(char target) 100 { 101 this->target = target; 102 } 103 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 118 ~TestBigDataBuilder() 119 { 120 std::cout << "~TestBigDataBuilder" << std::endl; 121 } 122 123private: 124 char target; 125}; 126 127class PurgeableCppTest : public testing::Test { 128public: 129 static void SetUpTestCase(); 130 static void TearDownTestCase(); 131 void SetUp(); 132 void TearDown(); 133}; 134 135void PurgeableCppTest::SetUpTestCase() 136{ 137} 138 139void PurgeableCppTest::TearDownTestCase() 140{ 141} 142 143void PurgeableCppTest::SetUp() 144{ 145} 146 147void PurgeableCppTest::TearDown() 148{ 149} 150 151HWTEST_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 199HWTEST_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 222HWTEST_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 250HWTEST_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 282HWTEST_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 311HWTEST_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 345HWTEST_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 381HWTEST_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 421HWTEST_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 435HWTEST_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 448void 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 462bool 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 481void 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 493void 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