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
40 namespace {
41 typedef struct {
42 int data[DATA_SIZE];
43 } StaticSpace;
44
45 const static int STATIC_DEPTH = 5;
46
47 static double g_mallocDuration = 0;
48 static double g_callocDuration = 0;
49 static double g_reallocDuration = 0;
50 static double g_freeDuration = 0;
51
52 static int g_fd = -1;
53 static int g_runing = 1;
54 static int g_threadNum = 1;
55 static int g_mallocSize = 1;
56 static const char* TEST_FILE_NAME = "./mmapTest";
57 static unsigned int g_hookFlag = 0;
58
DepthMalloc(int depth,int mallocSize)59 static 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
DepthCalloc(int depth,int callocSize)72 static 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
DepthRealloc(int depth,void * p,int reallocSize)82 static 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
DepthFree(int depth,void * p)92 static 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
ApplyForMalloc(int mallocSize)103 static 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
ApplyForCalloc(int mallocSize)129 static 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
ApplyForRealloc(int mallocSize)156 static 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
NewString()194 static 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
UniqueString()201 static void UniqueString()
202 {
203 auto pName = std::make_unique<std::string>("Hello");
204 }
205
206
ThreadFuncC(void * param)207 static 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 // 打开文件到内存中
OpenFile(const char * fileName)257 static 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 // 关闭文件
CloseFile(void)268 static void CloseFile(void)
269 {
270 if (g_fd > 0) {
271 close(g_fd);
272 g_fd = -1;
273 }
274 }
275
276 // 给文件建立内存映射
CreateMmap(void)277 static 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 // 关闭文件内存映射
RemoveMmap(char * pMap)301 static void RemoveMmap(char* pMap)
302 {
303 munmap(pMap, PAGE_SIZE);
304 }
305
306 // 给文件映射中写入
MmapWriteFile(char * pMap,int length,const char * data)307 static 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 // 从文件映射中读取
MmapReadFile(const char * pMap,int length)317 static 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
RandSrand(void)331 static void RandSrand(void)
332 {
333 srand(static_cast<unsigned>(time(nullptr)));
334 }
335
336 // 10 ~ 4096
RandInt(int max,int min)337 static int RandInt(int max, int min)
338 {
339 int value = (rand() % (max - min)) + min;
340 return value;
341 }
342
343 // 生成一个随机字符 (0x20 ~ 0x7E)
RandChar(void)344 static 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 // 获取随机长度的字符串
RandString(int maxLength)354 static 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 // 初始化函数
MmapInit(void)372 static void MmapInit(void)
373 {
374 // 设置随机种子
375 RandSrand();
376 // 设置全局映射的目标文件
377 g_fd = OpenFile(TEST_FILE_NAME);
378 }
379
380 // 写映射
WriteMmap(const char * data)381 static void WriteMmap(const char* data)
382 {
383 // 建立映射
384 char* pMap = CreateMmap();
385 if (data == nullptr || strlen(data) == 0) {
386 RemoveMmap(pMap);
387 return;
388 }
389 // 写入
390 MmapWriteFile(pMap, strlen(data), data);
391 // 关闭映射
392 RemoveMmap(pMap);
393 }
394
395 // 读映射
ReadMmap(int length)396 static char* ReadMmap(int length)
397 {
398 // 建立映射
399 char* pMap = CreateMmap();
400
401 // 写入
402 char* outTestchar = MmapReadFile(pMap, length);
403
404 // 关闭映射
405 RemoveMmap(pMap);
406
407 return outTestchar;
408 }
409
ThreadMmap(void * param)410 static void* ThreadMmap(void* param)
411 {
412 while (g_runing != 0) {
413 // 获取随机字符
414 char* randString = RandString(PAGE_SIZE);
415 if (randString == nullptr) {
416 continue;
417 }
418 // 写入映射
419 WriteMmap(randString);
420 // 从映射中读取
421 char* outchar = ReadMmap(strlen(randString));
422 printf("thread %ld : Mmap test OK! \n", syscall(SYS_gettid));
423 free(randString);
424 free(outchar);
425 sleep(SLEEP_TIME_SEC);
426 }
427 return nullptr;
428 }
429
430 // 维护hook test类型管理
BitMapNum(unsigned int data)431 static int BitMapNum(unsigned int data)
432 {
433 unsigned int tmp = data;
434 int num = 0;
435 while (tmp != 0) {
436 if ((tmp & 1) != 0) {
437 num++;
438 }
439 tmp >>= 1;
440 }
441 return num;
442 }
443
444 // 参数解析
CommandParse(int argc,char ** argv)445 static int CommandParse(int argc, char** argv)
446 {
447 int result;
448 opterr = 0;
449 while ((result = getopt(argc, argv, "t:s:n:o:h:")) != -1) {
450 switch (result) {
451 case 't':
452 // hook test的类型
453 if (!strcmp("mmap", optarg)) {
454 printf("Type: %s \n", optarg);
455 g_hookFlag |= MMAP_FLAG;
456 } else if (!strcmp("alloc", optarg)) {
457 printf("Type: %s \n", optarg);
458 g_hookFlag |= ALLOC_FLAG;
459 } else if (!strcmp("all", optarg)) {
460 printf("Type: %s \n", optarg);
461 g_hookFlag |= ALLOC_FLAG;
462 g_hookFlag |= MMAP_FLAG;
463 }
464 break;
465 case 's':
466 // 栈大小
467 g_mallocSize = atoi(optarg);
468 if (g_mallocSize <= 0) {
469 printf("Invalid mallocSize\n");
470 return -1;
471 }
472 break;
473 case 'n':
474 // 线程数
475 g_threadNum = atoi(optarg);
476 if (g_threadNum <= 0) {
477 printf("Invalid threadNum.\n");
478 return -1;
479 }
480 break;
481 case 'o':
482 TEST_FILE_NAME = optarg;
483 break;
484 case 'h':
485 default:
486 printf("%s -t <alloc/mmap>\n", argv[0]);
487 printf("\talloc : -s [alloc mallocSize] -n [thread Num]\n");
488 printf("\t mmap : -o [mmap datafile]\n");
489 return -1;
490 }
491 }
492 return opterr;
493 }
494 } // namespace
495
main(int argc,char * argv[])496 int main(int argc, char* argv[])
497 {
498 // 参数解析
499 int ret = CommandParse(argc, argv);
500 if (ret == -1) {
501 return 0;
502 }
503 int typeNum = BitMapNum(g_hookFlag);
504 printf(" g_hookFlag = [%u] \n", g_hookFlag);
505 if (typeNum == 0) {
506 // 未设置type时默认启动alloc
507 g_hookFlag |= ALLOC_FLAG;
508 typeNum++;
509 }
510
511 pthread_t** thrArrayList = static_cast<pthread_t**>(malloc(sizeof(pthread_t*) * typeNum));
512 if (thrArrayList == nullptr) {
513 printf("malloc thrArrayList fail\n");
514 return 0;
515 }
516 int type = 0;
517 if ((g_hookFlag & ALLOC_FLAG) != 0) {
518 int threadNum = g_threadNum;
519 int mallocSize = g_mallocSize;
520
521 pid_t pid = getpid();
522 printf("Process pid %d, Test start %d thread, malloc %d size\n", pid, threadNum, mallocSize);
523
524 thrArrayList[type] = static_cast<pthread_t*>(malloc(sizeof(pthread_t) * threadNum));
525 // pthread_t* thrArray
526 if (thrArrayList[type] == nullptr) {
527 printf("new thread failed.\n");
528 }
529 int idx;
530 for (idx = 0; idx < threadNum; ++idx) {
531 int result = pthread_create((thrArrayList[type]) + idx, nullptr,
532 ThreadFuncC, static_cast<void*>(&mallocSize));
533 if (result != 0) {
534 printf("Creating thread failed.\n");
535 }
536 }
537 type++;
538 }
539
540 if ((g_hookFlag & MMAP_FLAG) != 0) {
541 int threadNum = g_threadNum;
542 // 初始化
543 MmapInit();
544
545 thrArrayList[type] = static_cast<pthread_t*>(malloc(sizeof(pthread_t) * threadNum));
546 if (thrArrayList[type] == nullptr) {
547 printf("new thread failed.\n");
548 }
549
550 int idx;
551 for (idx = 0; idx < threadNum; ++idx) {
552 int result = pthread_create((thrArrayList[type]) + idx,
553 nullptr, ThreadMmap, nullptr);
554 if (result != 0) {
555 printf("Creating thread failed.\n");
556 }
557 }
558 }
559
560 while (getchar() != '\n') {
561 usleep(RESPONSE_SPEED);
562 };
563 g_runing = 0;
564 int idx;
565 for (type = 0; type < typeNum; type++) {
566 for (idx = 0; idx < g_threadNum; ++idx) {
567 pthread_join((thrArrayList[type])[idx], nullptr);
568 }
569 if (thrArrayList[type] != nullptr) {
570 free(thrArrayList[type]);
571 thrArrayList[type] = nullptr;
572 }
573 }
574 if (thrArrayList != nullptr) {
575 free(thrArrayList);
576 thrArrayList = nullptr;
577 }
578 CloseFile();
579 return 0;
580 }
581
582 #pragma clang optimize on
583