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 
41 const int DEFAULT_REALLOC_SIZE = 100;
42 const int TEST_BRANCH_NUM = 3;
43 const int STATIC_DEPTH = 5;
44 
45 typedef struct {
46     int data[DATA_SIZE];
47 } StaticSpace;
48 
49 static double g_mallocDuration = 0;
50 static double g_callocDuration = 0;
51 static double g_reallocDuration = 0;
52 static double g_freeDuration = 0;
53 
54 static int g_fd = -1;
55 static int g_runing = 1;
56 static int g_threadNum = 1;
57 static int g_mallocSize = 1;
58 static char* g_fileName = "./mmapTest";
59 static unsigned int g_hookFlag = 0;
60 
DepthMalloc(int depth, int mallocSize)61 char* 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 
DepthCalloc(int depth, int callocSize)74 char* 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 
DepthRealloc(int depth, void* p, int reallocSize)84 char* 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 
DepthFree(int depth, void* p)94 void 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 
ApplyForMalloc(int mallocSize)105 void 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 
ApplyForCalloc(int mallocSize)131 void 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 
ApplyForRealloc(int mallocSize)158 void 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 
ThreadFuncC(void* param)195 void* 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 // 打开文件到内存中
OpenFile(const char* fileName)240 int 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 // 关闭文件
CloseFile(void)251 void CloseFile(void)
252 {
253     if (g_fd > 0) {
254         close(g_fd);
255         g_fd = -1;
256     }
257 }
258 
259 // 给文件建立内存映射
CreateMmap(void)260 char* 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 // 关闭文件内存映射
RemoveMmap(char* pMap)282 void RemoveMmap(char* pMap)
283 {
284     munmap(pMap, PAGE_SIZE);
285 }
286 
287 // 给文件映射中写入
MmapWriteFile(char* pMap, int length, char* data)288 void 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 // 从文件映射中读取
MmapReadFile(char* pMap, int length)298 char* 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 
RandSrand(void)316 static void RandSrand(void)
317 {
318     (void)srand((unsigned)time(NULL));
319 }
320 
321 // 10 ~ 4096
RandInt(int maxVal, int minVal)322 int RandInt(int maxVal, int minVal)
323 {
324     int value = (rand() % (maxVal - minVal)) + minVal;
325     return value;
326 }
327 
328 // 生成一个随机字符 (0x20 ~ 0x7E)
RandChar(void)329 char 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 // 获取随机长度的字符串
RandString(int maxLength)339 char* 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 // 初始化函数
MmapInit(void)357 void MmapInit(void)
358 {
359     // 设置随机种子
360     RandSrand();
361     // 设置全局映射的目标文件
362     g_fd = OpenFile(g_fileName);
363 }
364 
365 // 写映射
WriteMmap(char* data)366 void 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 // 读映射
ReadMmap(int length)380 char* 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 
ThreadMmap(void* param)394 void* 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类型管理
BitMapNum(unsigned int data)412 int 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 // 参数解析
CommandParse(int argc, char** argv)426 int 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 
main(int argc, char* argv[])476 int 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