1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 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 <fcntl.h> 17#include <pthread.h> 18#include <cstdio> 19#include <cstdlib> 20#include <string> 21#include <sys/mman.h> 22#include <sys/stat.h> 23#include <sys/syscall.h> 24#include <sys/types.h> 25#include <ctime> 26#include <unistd.h> 27#ifdef HOOK_ENABLE 28#include "memory_trace.h" 29#endif 30#include "securec.h" 31#pragma clang optimize off 32 33#define PAGE_SIZE 4096 34#define SLEEP_TIME_SEC 1 35#define RESPONSE_SPEED 300 36#define DATA_SIZE 50 37#define ALLOC_FLAG (1 << 0) 38#define MMAP_FLAG (1 << 1) 39 40namespace { 41typedef struct { 42 int data[DATA_SIZE]; 43} StaticSpace; 44 45const static int STATIC_DEPTH = 5; 46 47static double g_mallocDuration = 0; 48static double g_callocDuration = 0; 49static double g_reallocDuration = 0; 50static double g_freeDuration = 0; 51 52static int g_fd = -1; 53static int g_runing = 1; 54static int g_threadNum = 1; 55static int g_mallocSize = 1; 56static const char* TEST_FILE_NAME = "./mmapTest"; 57static unsigned int g_hookFlag = 0; 58 59static char* DepthMalloc(int depth, int mallocSize) 60{ 61 if (mallocSize <= 0) { 62 return nullptr; 63 } 64 StaticSpace staticeData; 65 if (depth == 0) { 66 staticeData.data[0] = 1; 67 return (char*)malloc(mallocSize); 68 } 69 return (DepthMalloc(depth - 1, mallocSize)); 70} 71 72static char* DepthCalloc(int depth, int callocSize) 73{ 74 StaticSpace staticeData; 75 if (depth == 0) { 76 staticeData.data[0] = 1; 77 return (char*)calloc(sizeof(char), callocSize); 78 } 79 return (DepthCalloc(depth - 1, callocSize)); 80} 81 82static char* DepthRealloc(int depth, void* p, int reallocSize) 83{ 84 StaticSpace staticeData; 85 if (depth == 0) { 86 staticeData.data[0] = 1; 87 return (char*)realloc(p, reallocSize); 88 } 89 return (DepthRealloc(depth - 1, p, reallocSize)); 90} 91 92static void DepthFree(int depth, void* p) 93{ 94 StaticSpace staticeData; 95 if (depth == 0) { 96 staticeData.data[0] = 1; 97 free(p); 98 return; 99 } 100 return (DepthFree(depth - 1, p)); 101} 102 103static void ApplyForMalloc(int mallocSize) 104{ 105 printf("\nstart malloc apply (size = %d)\n", mallocSize); 106 clock_t timerStart = 0; 107 clock_t timerStop = 0; 108 double duration = 0; 109 timerStart = clock(); 110 char* p = DepthMalloc(STATIC_DEPTH, mallocSize); 111 timerStop = clock(); 112 if (!p) { 113 printf("malloc failure\n"); 114 return; 115 } 116 duration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 117 g_mallocDuration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 118 printf("malloc success, malloc (%d) time is %f\n", mallocSize, duration); 119 printf("\nReady for free -- "); 120 timerStart = clock(); 121 DepthFree(STATIC_DEPTH, p); 122 timerStop = clock(); 123 duration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 124 g_freeDuration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 125 printf("free success, free time is %f\n", static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC); 126 printf("malloc apply success, total time is %f\n", duration); 127} 128 129static void ApplyForCalloc(int mallocSize) 130{ 131 int callocSize = mallocSize / sizeof(char); 132 printf("\nstart calloc apply (size = %d)\n", callocSize); 133 clock_t timerStart = 0; 134 clock_t timerStop = 0; 135 double duration = 0; 136 timerStart = clock(); 137 char* p = DepthCalloc(STATIC_DEPTH, callocSize); 138 timerStop = clock(); 139 if (!p) { 140 printf("calloc failure\n"); 141 return; 142 } 143 duration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 144 g_callocDuration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 145 printf("calloc success, calloc (%d) time is %f\n", callocSize, duration); 146 printf("\nReady for free -- "); 147 timerStart = clock(); 148 DepthFree(STATIC_DEPTH, p); 149 timerStop = clock(); 150 duration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 151 g_freeDuration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 152 printf("free success, free time is %f\n", static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC); 153 printf("calloc apply success, total time is %f\n", duration); 154} 155 156static void ApplyForRealloc(int mallocSize) 157{ 158 const int defaultReallocSize = 100; 159 int reallocSize = mallocSize * defaultReallocSize; 160 printf("\nstart realloc apply (size = %d)\n", reallocSize); 161 if (mallocSize <= 0) { 162 printf("Invalid mallocSize.\n"); 163 return; 164 } 165 clock_t timerStart = 0; 166 clock_t timerStop = 0; 167 double duration = 0; 168 char* p = static_cast<char*>(malloc(mallocSize)); 169 if (!p) { 170 printf("malloc failure\n"); 171 return; 172 } 173 timerStart = clock(); 174 char* np = DepthRealloc(STATIC_DEPTH, p, reallocSize); 175 timerStop = clock(); 176 if (!np) { 177 free(p); 178 printf("realloc failure\n"); 179 return; 180 } 181 duration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 182 g_reallocDuration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 183 printf("realloc success, realloc (%d) time is %f\n", reallocSize, duration); 184 printf("\nReady for free -- "); 185 timerStart = clock(); 186 DepthFree(STATIC_DEPTH, np); 187 timerStop = clock(); 188 duration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 189 g_freeDuration += static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC; 190 printf("free success, free time is %f\n", static_cast<double>(timerStop - timerStart) / CLOCKS_PER_SEC); 191 printf("realloc apply success, total time is %f\n", duration); 192} 193 194static void NewString() 195{ 196 std::string* sp = new std::string("hello world"); 197 printf("string sp = %s\n", sp->c_str()); 198 delete sp; 199} 200 201static void UniqueString() 202{ 203 auto pName = std::make_unique<std::string>("Hello"); 204} 205 206 207static void* ThreadFuncC(void* param) 208{ 209 int mallocCount = 0; 210 int callocCount = 0; 211 int reallocCount = 0; 212 int freeCount = 0; 213 int randNum = 0; 214 int tid = syscall(SYS_gettid); 215 int mallocSize = *static_cast<int*>(param); 216 printf("start thread %d\n", tid); 217 time_t tv = time(nullptr); 218 if (tv == -1) { 219 tv = 1; 220 } 221 222 unsigned int seed = static_cast<unsigned int>(tv); 223 const int testBranchNum = 3; 224 while (g_runing != 0) { 225 randNum = rand_r(&seed) % testBranchNum; 226 if (randNum == 0) { 227 ApplyForMalloc(mallocSize); 228 mallocCount++; 229 } else if (randNum == 1) { 230 ApplyForCalloc(mallocSize); 231 callocCount++; 232 } else { 233 ApplyForRealloc(mallocSize); 234 reallocCount++; 235 } 236 freeCount++; 237 238 NewString(); 239 UniqueString(); 240 sleep(SLEEP_TIME_SEC); 241 } 242 243 printf("thread %d malloc count[%d] totalTime[%f] meanTime[%f].\n", tid, 244 mallocCount, g_mallocDuration, g_mallocDuration / mallocCount); 245 printf("thread %d calloc count[%d] totalTime[%f] meanTime[%f].\n", tid, 246 callocCount, g_callocDuration, g_callocDuration / callocCount); 247 printf("thread %d realloc count[%d] totalTime[%f] meanTime[%f].\n", tid, 248 reallocCount, g_reallocDuration, g_reallocDuration / reallocCount); 249 printf("thread %d free count[%d] totalTime[%f] meanTime[%f].\n", tid, 250 freeCount, g_freeDuration, g_freeDuration / freeCount); 251 printf("finish thread %d\n", tid); 252 253 return nullptr; 254} 255 256// 打开文件到内存中 257static int OpenFile(const char* fileName) 258{ 259 int fd = open(fileName, O_RDWR | O_CREAT, static_cast<mode_t>(0644)); // 0644 rw-r--r-- 260 if (fd == -1) { 261 printf("can not open the file\n"); 262 return -1; 263 } 264 return fd; 265} 266 267// 关闭文件 268static void CloseFile(void) 269{ 270 if (g_fd > 0) { 271 close(g_fd); 272 g_fd = -1; 273 } 274} 275 276// 给文件建立内存映射 277static char* CreateMmap(void) 278{ 279 if (g_fd == -1) { 280 return nullptr; 281 } 282 283 int size = PAGE_SIZE; 284 lseek(g_fd, size + 1, SEEK_SET); 285 write(g_fd, "", 1); 286 287 char* pMap = static_cast<char*>(mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0)); 288 289#ifdef HOOK_ENABLE 290 const char *tag = "memtesttag"; 291 memtrace(pMap, PAGE_SIZE, tag, true); 292#endif 293 if (pMap == MAP_FAILED) { 294 printf("mmap fail\n"); 295 CloseFile(); 296 } 297 return pMap; 298} 299 300// 关闭文件内存映射 301static void RemoveMmap(char* pMap) 302{ 303 munmap(pMap, PAGE_SIZE); 304} 305 306// 给文件映射中写入 307static void MmapWriteFile(char* pMap, int length, const char* data) 308{ 309 if (memcpy_s(pMap, length, data, length) != EOK) { 310 printf("memcpy_s type fail\n"); 311 return; 312 } 313 msync(pMap, length, MS_SYNC); 314} 315 316// 从文件映射中读取 317static char* MmapReadFile(const char* pMap, int length) 318{ 319 if (length <= 0) { 320 printf("fail:malloc %d memory", length); 321 return nullptr; 322 } 323 char* data = static_cast<char*>(malloc(length + 1)); 324 if (data != nullptr) { 325 memcpy_s(data, length, pMap, length); 326 data[length] = '\0'; 327 } 328 return data; 329} 330 331static void RandSrand(void) 332{ 333 srand(static_cast<unsigned>(time(nullptr))); 334} 335 336// 10 ~ 4096 337static int RandInt(int max, int min) 338{ 339 int value = (rand() % (max - min)) + min; 340 return value; 341} 342 343// 生成一个随机字符 (0x20 ~ 0x7E) 344static char RandChar(void) 345{ 346 // 可显示字符的范围 347 int section = '~' - ' '; 348 int randSection = RandInt(0, section); 349 char randChar = '~' + static_cast<unsigned int>(randSection); 350 return randChar; 351} 352 353// 获取随机长度的字符串 354static char* RandString(int maxLength) 355{ 356 int strLength = RandInt(10, maxLength); 357 if (strLength <= 0) { 358 printf("fail:malloc %d memory", strLength); 359 return nullptr; 360 } 361 char* data = static_cast<char*>(malloc(strLength + 1)); 362 if (data != nullptr) { 363 for (int i = 0; i < strLength; i++) { 364 data[i] = RandChar(); 365 } 366 data[strLength] = '\0'; 367 } 368 return data; 369} 370 371// 初始化函数 372static void MmapInit(void) 373{ 374 // 设置随机种子 375 RandSrand(); 376 // 设置全局映射的目标文件 377 g_fd = OpenFile(TEST_FILE_NAME); 378} 379 380// 写映射 381static void WriteMmap(const char* data) 382{ 383 // 建立映射 384 char* pMap = CreateMmap(); 385 if (data == nullptr || strlen(data) == 0) { 386 return; 387 } 388 // 写入 389 MmapWriteFile(pMap, strlen(data), data); 390 // 关闭映射 391 RemoveMmap(pMap); 392} 393 394// 读映射 395static char* ReadMmap(int length) 396{ 397 // 建立映射 398 char* pMap = CreateMmap(); 399 400 // 写入 401 char* outTestchar = MmapReadFile(pMap, length); 402 403 // 关闭映射 404 RemoveMmap(pMap); 405 406 return outTestchar; 407} 408 409static void* ThreadMmap(void* param) 410{ 411 while (g_runing != 0) { 412 // 获取随机字符 413 char* randString = RandString(PAGE_SIZE); 414 415 // 写入映射 416 WriteMmap(randString); 417 418 // 从映射中读取 419 char* outchar = ReadMmap(strlen(randString)); 420 printf("thread %ld : Mmap test OK! \n", syscall(SYS_gettid)); 421 free(randString); 422 free(outchar); 423 sleep(SLEEP_TIME_SEC); 424 } 425 return nullptr; 426} 427 428// 维护hook test类型管理 429static int BitMapNum(unsigned int data) 430{ 431 unsigned int tmp = data; 432 int num = 0; 433 while (tmp != 0) { 434 if ((tmp & 1) != 0) { 435 num++; 436 } 437 tmp >>= 1; 438 } 439 return num; 440} 441 442// 参数解析 443static int CommandParse(int argc, char** argv) 444{ 445 int result; 446 opterr = 0; 447 while ((result = getopt(argc, argv, "t:s:n:o:h:")) != -1) { 448 switch (result) { 449 case 't': 450 // hook test的类型 451 if (!strcmp("mmap", optarg)) { 452 printf("Type: %s \n", optarg); 453 g_hookFlag |= MMAP_FLAG; 454 } else if (!strcmp("alloc", optarg)) { 455 printf("Type: %s \n", optarg); 456 g_hookFlag |= ALLOC_FLAG; 457 } else if (!strcmp("all", optarg)) { 458 printf("Type: %s \n", optarg); 459 g_hookFlag |= ALLOC_FLAG; 460 g_hookFlag |= MMAP_FLAG; 461 } 462 break; 463 case 's': 464 // 栈大小 465 g_mallocSize = atoi(optarg); 466 if (g_mallocSize <= 0) { 467 printf("Invalid mallocSize\n"); 468 return -1; 469 } 470 break; 471 case 'n': 472 // 线程数 473 g_threadNum = atoi(optarg); 474 if (g_threadNum <= 0) { 475 printf("Invalid threadNum.\n"); 476 return -1; 477 } 478 break; 479 case 'o': 480 TEST_FILE_NAME = optarg; 481 break; 482 case 'h': 483 default: 484 printf("%s -t <alloc/mmap>\n", argv[0]); 485 printf("\talloc : -s [alloc mallocSize] -n [thread Num]\n"); 486 printf("\t mmap : -o [mmap datafile]\n"); 487 return -1; 488 } 489 } 490 return opterr; 491} 492} // namespace 493 494int main(int argc, char* argv[]) 495{ 496 // 参数解析 497 int ret = CommandParse(argc, argv); 498 if (ret == -1) { 499 return 0; 500 } 501 int typeNum = BitMapNum(g_hookFlag); 502 printf(" g_hookFlag = [%u] \n", g_hookFlag); 503 if (typeNum == 0) { 504 // 未设置type时默认启动alloc 505 g_hookFlag |= ALLOC_FLAG; 506 typeNum++; 507 } 508 509 pthread_t** thrArrayList = static_cast<pthread_t**>(malloc(sizeof(pthread_t*) * typeNum)); 510 if (thrArrayList == nullptr) { 511 printf("malloc thrArrayList fail\n"); 512 return 0; 513 } 514 int type = 0; 515 if ((g_hookFlag & ALLOC_FLAG) != 0) { 516 int threadNum = g_threadNum; 517 int mallocSize = g_mallocSize; 518 519 pid_t pid = getpid(); 520 printf("Process pid %d, Test start %d thread, malloc %d size\n", pid, threadNum, mallocSize); 521 522 thrArrayList[type] = static_cast<pthread_t*>(malloc(sizeof(pthread_t) * threadNum)); 523 // pthread_t* thrArray 524 if (thrArrayList[type] == nullptr) { 525 printf("new thread failed.\n"); 526 } 527 int idx; 528 for (idx = 0; idx < threadNum; ++idx) { 529 int result = pthread_create((thrArrayList[type]) + idx, nullptr, 530 ThreadFuncC, static_cast<void*>(&mallocSize)); 531 if (result != 0) { 532 printf("Creating thread failed.\n"); 533 } 534 } 535 type++; 536 } 537 538 if ((g_hookFlag & MMAP_FLAG) != 0) { 539 int threadNum = g_threadNum; 540 // 初始化 541 MmapInit(); 542 543 thrArrayList[type] = static_cast<pthread_t*>(malloc(sizeof(pthread_t) * threadNum)); 544 if (thrArrayList[type] == nullptr) { 545 printf("new thread failed.\n"); 546 } 547 548 int idx; 549 for (idx = 0; idx < threadNum; ++idx) { 550 int result = pthread_create((thrArrayList[type]) + idx, 551 nullptr, ThreadMmap, nullptr); 552 if (result != 0) { 553 printf("Creating thread failed.\n"); 554 } 555 } 556 } 557 558 while (getchar() != '\n') { 559 usleep(RESPONSE_SPEED); 560 }; 561 g_runing = 0; 562 int idx; 563 for (type = 0; type < typeNum; type++) { 564 for (idx = 0; idx < g_threadNum; ++idx) { 565 pthread_join((thrArrayList[type])[idx], nullptr); 566 } 567 if (thrArrayList[type] != nullptr) { 568 free(thrArrayList[type]); 569 thrArrayList[type] = nullptr; 570 } 571 } 572 if (thrArrayList != nullptr) { 573 free(thrArrayList); 574 thrArrayList = nullptr; 575 } 576 CloseFile(); 577 return 0; 578} 579 580#pragma clang optimize on 581