• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         if (randString == NULL) {
400             continue;
401         }
402         // 写入映射
403         WriteMmap(randString);
404         // 从映射中读取
405         char* outchar = ReadMmap(strlen(randString));
406         printf("thread %ld : Mmap test OK! \n", syscall(SYS_gettid));
407         free(randString);
408         free(outchar);
409         sleep(SLEEP_TIME_SEC);
410     }
411     return NULL;
412 }
413 
414 // 维护hook test类型管理
BitMapNum(unsigned int data)415 int BitMapNum(unsigned int data)
416 {
417     unsigned int tmp = data;
418     int num = 0;
419     while (tmp) {
420         if (tmp & 1) {
421             num++;
422         }
423         tmp >>= 1;
424     }
425     return num;
426 }
427 
428 // 参数解析
CommandParse(int argc,char ** argv)429 int CommandParse(int argc, char** argv)
430 {
431     int result;
432     opterr = 0;
433     while ((result = getopt(argc, argv, "t:s:n:o:h:")) != -1) {
434         switch (result) {
435             case 't':
436                 // hook test的类型
437                 if (!strcmp("mmap", optarg)) {
438                     printf("Type: %s \n", optarg);
439                     g_hookFlag |= MMAP_FLAG;
440                 } else if (!strcmp("alloc", optarg)) {
441                     printf("Type: %s \n", optarg);
442                     g_hookFlag |= ALLOC_FLAG;
443                 } else if (!strcmp("all", optarg)) {
444                     printf("Type: %s \n", optarg);
445                     g_hookFlag |= ALLOC_FLAG;
446                     g_hookFlag |= MMAP_FLAG;
447                 }
448                 break;
449             case 's':
450                 // 栈大小
451                 g_mallocSize = atoi(optarg);
452                 if (g_mallocSize <= 0) {
453                     printf("Invalid mallocSize\n");
454                     return -1;
455                 }
456                 break;
457             case 'n':
458                 // 线程数
459                 g_threadNum = atoi(optarg);
460                 if (g_threadNum <= 0) {
461                     printf("Invalid threadNum.\n");
462                     return -1;
463                 }
464                 break;
465             case 'o':
466                 g_fileName = optarg;
467                 break;
468             case 'h':
469             default:
470                 printf("%s -t <alloc/mmap>\n", argv[0]);
471                 printf("\talloc : -s [alloc mallocSize] -n [thread Num]\n");
472                 printf("\t mmap : -o [mmap datafile]\n");
473                 return -1;
474         }
475     }
476     return opterr;
477 }
478 
main(int argc,char * argv[])479 int main(int argc, char* argv[])
480 {
481     // 参数解析
482     int ret = CommandParse(argc, argv);
483     if (ret == -1) {
484         return 0;
485     }
486     int typeNum = BitMapNum(g_hookFlag);
487     printf(" g_hookFlag =  [%x] \n", g_hookFlag);
488     if (typeNum == 0) {
489         // 未设置type时默认启动alloc
490         g_hookFlag |= ALLOC_FLAG;
491         typeNum++;
492     }
493 
494     pthread_t** thrArrayList = (pthread_t**)malloc(sizeof(pthread_t*) * typeNum);
495     if (thrArrayList == NULL) {
496         printf("malloc thrArrayList fail\n");
497         return 0;
498     }
499     int type = 0;
500     if (g_hookFlag & ALLOC_FLAG) {
501         int threadNum = g_threadNum;
502         int mallocSize = g_mallocSize;
503 
504         pid_t pid = getpid();
505         printf("Process pid %d, Test start %d thread, malloc %d size\n", pid, threadNum, mallocSize);
506 
507         thrArrayList[type] = (pthread_t*)malloc(sizeof(pthread_t) * threadNum);
508         // pthread_t* thrArray
509         if (thrArrayList[type] == NULL) {
510             printf("new thread failed.\n");
511             if (thrArrayList != NULL) {
512                 free(thrArrayList);
513                 thrArrayList = NULL;
514             }
515             return 0;
516         }
517         int idx;
518         for (idx = 0; idx < threadNum; ++idx) {
519             if (pthread_create((thrArrayList[type]) + idx, NULL, ThreadFuncC, (void*)(&mallocSize))) {
520                 printf("Creating thread failed.\n");
521             }
522         }
523         type++;
524     }
525 
526     if (g_hookFlag & MMAP_FLAG) {
527         int threadNum = g_threadNum;
528         // 初始化
529         MmapInit();
530 
531         thrArrayList[type] = (pthread_t*)malloc(sizeof(pthread_t) * threadNum);
532         if (thrArrayList[type] == NULL) {
533             printf("new thread failed.\n");
534             if (thrArrayList != NULL) {
535                 free(thrArrayList);
536                 thrArrayList = NULL;
537             }
538             CloseFile();
539             return 0;
540         }
541 
542         int idx;
543         for (idx = 0; idx < threadNum; ++idx) {
544             if (pthread_create((thrArrayList[type]) + idx, NULL, ThreadMmap, NULL)) {
545                 printf("Creating thread failed.\n");
546             }
547         }
548     }
549 
550     while (getchar() != '\n') {
551         usleep(RESPONSE_SPEED);
552     };
553     g_runing = 0;
554     int idx;
555     for (type = 0; type < typeNum; type++) {
556         for (idx = 0; idx < g_threadNum; ++idx) {
557             pthread_join((thrArrayList[type])[idx], NULL);
558         }
559         if (thrArrayList[type] != NULL) {
560             free(thrArrayList[type]);
561             thrArrayList[type] = NULL;
562         }
563     }
564     if (thrArrayList != NULL) {
565         free(thrArrayList);
566         thrArrayList = NULL;
567     }
568     CloseFile();
569     return 0;
570 }
571 
572 #pragma clang optimize on
573