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