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