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