• 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 <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