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