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