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 <sys/mman.h>
22 #include <sys/stat.h>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <time.h>
26 #include <unistd.h>
27 #ifdef HOOK_ENABLE
28 #include "memory_tag.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 const int DEFAULT_REALLOC_SIZE = 100;
41 const int TEST_BRANCH_NUM = 3;
42 const int STATIC_DEPTH = 5;
43
44 typedef struct {
45 int data[DATA_SIZE];
46 } StaticSpace;
47
48 static double g_mallocDuration = 0;
49 static double g_callocDuration = 0;
50 static double g_reallocDuration = 0;
51 static double g_freeDuration = 0;
52
53 static int g_fd = -1;
54 static int g_runing = 1;
55 static int g_threadNum = 1;
56 static int g_mallocSize = 1;
57 static char* g_fileName = "./mmapTest";
58 static unsigned int g_hook_flag = 0;
59
DepthMalloc(int depth,int mallocSize)60 char* DepthMalloc(int depth, int mallocSize)
61 {
62 if (mallocSize <= 0) {
63 return NULL;
64 }
65 StaticSpace staticeData;
66 if (depth == 0) {
67 staticeData.data[0] = 1;
68 return (char*)malloc(mallocSize);
69 }
70 return (DepthMalloc(depth - 1, mallocSize));
71 }
72
DepthCalloc(int depth,int callocSize)73 char* DepthCalloc(int depth, int callocSize)
74 {
75 StaticSpace staticeData;
76 if (depth == 0) {
77 staticeData.data[0] = 1;
78 return (char*)calloc(sizeof(char), callocSize);
79 }
80 return (DepthCalloc(depth - 1, callocSize));
81 }
82
DepthRealloc(int depth,void * p,int reallocSize)83 char* DepthRealloc(int depth, void* p, int reallocSize)
84 {
85 StaticSpace staticeData;
86 if (depth == 0) {
87 staticeData.data[0] = 1;
88 return (char*)realloc(p, reallocSize);
89 }
90 return (DepthRealloc(depth - 1, p, reallocSize));
91 }
92
DepthFree(int depth,void * p)93 void DepthFree(int depth, void* p)
94 {
95 StaticSpace staticeData;
96 if (depth == 0) {
97 staticeData.data[0] = 1;
98 free(p);
99 return;
100 }
101 return (DepthFree(depth - 1, p));
102 }
103
ApplyForMalloc(int mallocSize)104 void ApplyForMalloc(int mallocSize)
105 {
106 printf("\nstart malloc apply (size = %d)\n", mallocSize);
107 clock_t timerStart = 0;
108 clock_t timerStop = 0;
109 double duration = 0;
110 timerStart = clock();
111 char* p = DepthMalloc(STATIC_DEPTH, mallocSize);
112 timerStop = clock();
113 if (!p) {
114 printf("malloc failure\n");
115 return;
116 }
117 duration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
118 g_mallocDuration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
119 printf("malloc success, malloc (%d) time is %f\n", mallocSize, duration);
120 printf("\nReady for free -- ");
121 timerStart = clock();
122 DepthFree(STATIC_DEPTH, p);
123 timerStop = clock();
124 duration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
125 g_freeDuration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
126 printf("free success, free time is %f\n", (double)(timerStop - timerStart) / CLOCKS_PER_SEC);
127 printf("malloc apply success, total time is %f\n", duration);
128 }
129
ApplyForCalloc(int mallocSize)130 void ApplyForCalloc(int mallocSize)
131 {
132 int callocSize = mallocSize / sizeof(char);
133 printf("\nstart calloc apply (size = %d)\n", callocSize);
134 clock_t timerStart = 0;
135 clock_t timerStop = 0;
136 double duration = 0;
137 timerStart = clock();
138 char* p = DepthCalloc(STATIC_DEPTH, callocSize);
139 timerStop = clock();
140 if (!p) {
141 printf("calloc failure\n");
142 return;
143 }
144 duration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
145 g_callocDuration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
146 printf("calloc success, calloc (%d) time is %f\n", callocSize, duration);
147 printf("\nReady for free -- ");
148 timerStart = clock();
149 DepthFree(STATIC_DEPTH, p);
150 timerStop = clock();
151 duration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
152 g_freeDuration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
153 printf("free success, free time is %f\n", (double)(timerStop - timerStart) / CLOCKS_PER_SEC);
154 printf("calloc apply success, total time is %f\n", duration);
155 }
156
ApplyForRealloc(int mallocSize)157 void ApplyForRealloc(int mallocSize)
158 {
159 int reallocSize = mallocSize * DEFAULT_REALLOC_SIZE;
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 += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
182 g_reallocDuration += (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 += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
189 g_freeDuration += (double)(timerStop - timerStart) / CLOCKS_PER_SEC;
190 printf("free success, free time is %f\n", (double)(timerStop - timerStart) / CLOCKS_PER_SEC);
191 printf("realloc apply success, total time is %f\n", duration);
192 }
193
ThreadFuncC(void * param)194 void* ThreadFuncC(void* param)
195 {
196 int mallocCount = 0;
197 int callocCount = 0;
198 int reallocCount = 0;
199 int freeCount = 0;
200 int randNum = 0;
201 int tid = syscall(SYS_gettid);
202 int mallocSize = *(int*)param;
203 printf("start thread %d\n", tid);
204 time_t tv = time(NULL);
205 if (tv == -1) {
206 tv = 1;
207 }
208 unsigned int seed = (unsigned int)tv;
209 while (g_runing) {
210 randNum = rand_r(&seed) % TEST_BRANCH_NUM;
211 if (randNum == 0) {
212 ApplyForMalloc(mallocSize);
213 mallocCount++;
214 } else if (randNum == 1) {
215 ApplyForCalloc(mallocSize);
216 callocCount++;
217 } else {
218 ApplyForRealloc(mallocSize);
219 reallocCount++;
220 }
221 freeCount++;
222 sleep(SLEEP_TIME_SEC);
223 }
224
225 printf("thread %d malloc count[%d] totalTime[%f] meanTime[%f].\n", tid,
226 mallocCount, g_mallocDuration, g_mallocDuration / mallocCount);
227 printf("thread %d calloc count[%d] totalTime[%f] meanTime[%f].\n", tid,
228 callocCount, g_callocDuration, g_callocDuration / callocCount);
229 printf("thread %d realloc count[%d] totalTime[%f] meanTime[%f].\n", tid,
230 reallocCount, g_reallocDuration, g_reallocDuration / reallocCount);
231 printf("thread %d free count[%d] totalTime[%f] meanTime[%f].\n", tid,
232 freeCount, g_freeDuration, g_freeDuration / freeCount);
233 printf("finish thread %d\n", tid);
234
235 return NULL;
236 }
237
238 // 打开文件到内存中
OpenFile(const char * fileName)239 int OpenFile(const char* fileName)
240 {
241 int fd = open(fileName, O_RDWR | O_CREAT, (mode_t)0777);
242 if (fd == -1) {
243 printf("can not open the file\n");
244 return -1;
245 }
246 return fd;
247 }
248
249 // 关闭文件
CloseFile(void)250 void CloseFile(void)
251 {
252 if (g_fd > 0) {
253 close(g_fd);
254 g_fd = -1;
255 }
256 }
257
258 // 给文件建立内存映射
CreateMmap(void)259 char* CreateMmap(void)
260 {
261 if (g_fd == -1) {
262 return NULL;
263 }
264 int size = PAGE_SIZE;
265 lseek(g_fd, size + 1, SEEK_SET);
266 write(g_fd, "", 1);
267
268 char* pMap = (char*)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0);
269 #ifdef HOOK_ENABLE
270 char *tag = "memtesttag";
271 MEM_TYPESET(pMap, PAGE_SIZE, tag, strlen(tag)+1);
272 #endif
273 if (pMap == MAP_FAILED) {
274 printf("mmap fail\n");
275 CloseFile();
276 }
277 return pMap;
278 }
279
280 // 关闭文件内存映射
RemoveMmap(char * pMap)281 void RemoveMmap(char* pMap)
282 {
283 munmap(pMap, PAGE_SIZE);
284 }
285
286 // 给文件映射中写入
MmapWriteFile(char * pMap,int length,char * data)287 void MmapWriteFile(char* pMap, int length, char* data)
288 {
289 if (memcpy_s(pMap, length, data, length) != EOK) {
290 printf("memcpy_s type fail\n");
291 return;
292 }
293 msync(pMap, length, MS_SYNC);
294 }
295
296 // 从文件映射中读取
MmapReadFile(char * pMap,int length)297 char* MmapReadFile(char* pMap, int length)
298 {
299 if (length <= 0) {
300 printf("fail:malloc %d memory", length);
301 return NULL;
302 }
303 char* data = (char*)malloc(length + 1);
304 if (data != NULL) {
305 if (memcpy_s(data, length+1, pMap, length) != EOK) {
306 printf("memcpy_s type fail\n");
307 free(data);
308 return NULL;
309 }
310 data[length] = '\0';
311 }
312 return data;
313 }
314
RandSrand(void)315 static void RandSrand(void)
316 {
317 srand((unsigned)time(NULL));
318 }
319
320 // 10 ~ 4096
RandInt(int Max,int Min)321 int RandInt(int Max, int Min)
322 {
323 int value = (rand() % (Max - Min)) + Min;
324 return value;
325 }
326
327 // 生成一个随机字符 (0x20 ~ 0x7E)
RandChar(void)328 char RandChar(void)
329 {
330 // 可显示字符的范围
331 int section = '~' - ' ';
332 int randSection = RandInt(0, section);
333 char randChar = (char)('~' + (unsigned int)randSection);
334 return randChar;
335 }
336
337 // 获取随机长度的字符串
RandString(int maxLength)338 char* RandString(int maxLength)
339 {
340 int strLength = RandInt(10, maxLength);
341 if (strLength <= 0) {
342 printf("fail:malloc %d memory", strLength);
343 return NULL;
344 }
345 char* data = (char*)malloc(strLength + 1);
346 if (data != NULL) {
347 for (int i = 0; i < strLength; i++) {
348 data[i] = RandChar();
349 }
350 data[strLength] = '\0';
351 }
352 return data;
353 }
354
355 // 初始化函数
mmapInit(void)356 void mmapInit(void)
357 {
358 // 设置随机种子
359 RandSrand();
360 // 设置全局映射的目标文件
361 g_fd = OpenFile(g_fileName);
362 }
363
364 // 写映射
WriteMmap(char * data)365 void WriteMmap(char* data)
366 {
367 // 建立映射
368 char* pMap = CreateMmap();
369 // 写入
370 MmapWriteFile(pMap, strlen(data), data);
371
372 // 关闭映射
373 RemoveMmap(pMap);
374 }
375
376 // 读映射
ReadMmap(int length)377 char* ReadMmap(int length)
378 {
379 // 建立映射
380 char* pMap = CreateMmap();
381
382 // 写入
383 char* outTestchar = MmapReadFile(pMap, length);
384
385 // 关闭映射
386 RemoveMmap(pMap);
387
388 return outTestchar;
389 }
390
ThreadMmap(void * param)391 void* ThreadMmap(void* param)
392 {
393 while (g_runing) {
394 // 获取随机字符
395 char* randString = RandString(PAGE_SIZE);
396 // 写入映射
397 WriteMmap(randString);
398 // 从映射中读取
399 char* outchar = ReadMmap(strlen(randString));
400 printf("thread %ld : Mmap test OK! \n", syscall(SYS_gettid));
401 free(randString);
402 free(outchar);
403 sleep(SLEEP_TIME_SEC);
404 }
405 return NULL;
406 }
407
408 // 维护hook test类型管理
bitMapNum(unsigned int data)409 int bitMapNum(unsigned int data)
410 {
411 unsigned int tmp = data;
412 int num = 0;
413 while (tmp) {
414 if (tmp & 1) {
415 num++;
416 }
417 tmp >>= 1;
418 }
419 return num;
420 }
421
422 // 参数解析
CommandParse(int argc,char ** argv)423 int CommandParse(int argc, char** argv)
424 {
425 int result;
426 opterr = 0;
427 while ((result = getopt(argc, argv, "t:s:n:o:h:")) != -1) {
428 switch (result) {
429 case 't':
430 // hook test的类型
431 if (!strcmp("mmap", optarg)) {
432 printf("Type: %s \n", optarg);
433 g_hook_flag |= MMAP_FLAG;
434 } else if (!strcmp("alloc", optarg)) {
435 printf("Type: %s \n", optarg);
436 g_hook_flag |= ALLOC_FLAG;
437 } else if (!strcmp("all", optarg)) {
438 printf("Type: %s \n", optarg);
439 g_hook_flag |= ALLOC_FLAG;
440 g_hook_flag |= MMAP_FLAG;
441 }
442 break;
443 case 's':
444 // 栈大小
445 g_mallocSize = atoi(optarg);
446 if (g_mallocSize <= 0) {
447 printf("Invalid mallocSize\n");
448 return -1;
449 }
450 break;
451 case 'n':
452 // 线程数
453 g_threadNum = atoi(optarg);
454 if (g_threadNum <= 0) {
455 printf("Invalid threadNum.\n");
456 return -1;
457 }
458 break;
459 case 'o':
460 g_fileName = optarg;
461 break;
462 case 'h':
463 default:
464 printf("%s -t <alloc/mmap>\n", argv[0]);
465 printf("\talloc : -s [alloc mallocSize] -n [thread Num]\n");
466 printf("\t mmap : -o [mmap datafile]\n");
467 return -1;
468 }
469 }
470 return opterr;
471 }
472
main(int argc,char * argv[])473 int main(int argc, char* argv[])
474 {
475 // 参数解析
476 int ret = CommandParse(argc, argv);
477 if (ret == -1) {
478 return 0;
479 }
480 int typeNum = bitMapNum(g_hook_flag);
481 printf(" g_hook_flag = [%x] \n", g_hook_flag);
482 if (typeNum == 0) {
483 // 未设置type时默认启动alloc
484 g_hook_flag |= ALLOC_FLAG;
485 typeNum++;
486 }
487
488 pthread_t** thrArrayList = (pthread_t**)malloc(sizeof(pthread_t*) * typeNum);
489 if (thrArrayList == NULL) {
490 printf("malloc thrArrayList fail\n");
491 return 0;
492 }
493 int type = 0;
494 if (g_hook_flag & ALLOC_FLAG) {
495 int threadNum = g_threadNum;
496 int mallocSize = g_mallocSize;
497
498 pid_t pid = getpid();
499 printf("Process pid %d, Test start %d thread, malloc %d size\n", pid, threadNum, mallocSize);
500
501 thrArrayList[type] = (pthread_t*)malloc(sizeof(pthread_t) * threadNum);
502 // pthread_t* thrArray
503 if (thrArrayList[type] == NULL) {
504 printf("new thread failed.\n");
505 if (thrArrayList != NULL) {
506 free(thrArrayList);
507 thrArrayList = NULL;
508 }
509 return 0;
510 }
511 int idx;
512 for (idx = 0; idx < threadNum; ++idx) {
513 if (pthread_create((thrArrayList[type]) + idx, NULL, ThreadFuncC, (void*)(&mallocSize))) {
514 printf("Creating thread failed.\n");
515 }
516 }
517 type++;
518 }
519
520 if (g_hook_flag & MMAP_FLAG) {
521 int threadNum = g_threadNum;
522 // 初始化
523 mmapInit();
524
525 thrArrayList[type] = (pthread_t*)malloc(sizeof(pthread_t) * threadNum);
526 if (thrArrayList[type] == NULL) {
527 printf("new thread failed.\n");
528 if (thrArrayList != NULL) {
529 free(thrArrayList);
530 thrArrayList = NULL;
531 }
532 CloseFile();
533 return 0;
534 }
535
536 int idx;
537 for (idx = 0; idx < threadNum; ++idx) {
538 if (pthread_create((thrArrayList[type]) + idx, NULL, ThreadMmap, NULL)) {
539 printf("Creating thread failed.\n");
540 }
541 }
542 }
543
544 while (getchar() != '\n') {
545 usleep(RESPONSE_SPEED);
546 };
547 g_runing = 0;
548 int idx;
549 for (type = 0; type < typeNum; type++) {
550 for (idx = 0; idx < g_threadNum; ++idx) {
551 pthread_join((thrArrayList[type])[idx], NULL);
552 }
553 if (thrArrayList[type] != NULL) {
554 free(thrArrayList[type]);
555 thrArrayList[type] = NULL;
556 }
557 }
558 if (thrArrayList != NULL) {
559 free(thrArrayList);
560 thrArrayList = NULL;
561 }
562 CloseFile();
563 return 0;
564 }
565
566 #pragma clang optimize on
567