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