1 /*
2  * Copyright (C) 2023 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 <iostream>
17 #include <map>
18 #include <string>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <securec.h>
22 #include "hc_mutex.h"
23 #include "memory_monitor.h"
24 
25 using namespace std;
26 
27 #define MAX_MALLOC_SIZE 8192
28 #define MALLOC_MAX_LINE_STR_LEN 11
29 
30 static const int MALLOC_SIZE[] = { 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
31 
GetRealMallocSize(int size)32 static int GetRealMallocSize(int size)
33 {
34     for (unsigned int i = 0; i < sizeof(MALLOC_SIZE) / sizeof(int); ++i) {
35         if (size <= MALLOC_SIZE[i]) {
36             return MALLOC_SIZE[i];
37         }
38     }
39     return MAX_MALLOC_SIZE;
40 }
41 
42 typedef struct {
43     uint32_t id;
44     uint32_t size;
45     uint32_t realSize;
46     string str;
47 } MemoryBlock;
48 
49 static map<void*, MemoryBlock> gMemoryMap;
50 
51 static bool g_isInit = false;
52 
53 static int g_mallocCount = 0;
54 static int g_maxCount = 0;
55 static int g_maxSingleCount = 0;
56 static int g_count = 0;
57 
58 static HcMutex *g_mutex = NULL;
59 
HcMonitorMalloc(void * addr,uint32_t size,const char * strFile,int nLine)60 void HcMonitorMalloc(void *addr, uint32_t size, const char *strFile, int nLine)
61 {
62     if (!g_isInit) {
63         return;
64     }
65     g_mutex->lock(g_mutex);
66     map<void *, MemoryBlock>::iterator iter = gMemoryMap.find(addr);
67     if (iter != gMemoryMap.end()) {
68         cout << "############## Monitor Malloc error, addr is alread exist!" << endl;
69     } else {
70         int realSize = GetRealMallocSize(size);
71         MemoryBlock mb;
72         mb.size = size;
73         mb.realSize = realSize;
74         mb.id = g_count++;
75         char strLine[MALLOC_MAX_LINE_STR_LEN];
76         if (sprintf_s(strLine, MALLOC_MAX_LINE_STR_LEN, "%d", nLine) <= 0) {
77             g_mutex->unlock(g_mutex);
78             return;
79         }
80         mb.str = strFile;
81         mb.str += ":";
82         mb.str += strLine;
83         gMemoryMap[addr] = mb;
84         g_mallocCount += realSize;
85         if (g_maxCount < g_mallocCount) {
86             g_maxCount = g_mallocCount;
87         }
88         if (g_maxSingleCount < realSize) {
89             g_maxSingleCount = realSize;
90         }
91     }
92     g_mutex->unlock(g_mutex);
93 }
94 
HcMonitorFree(void * addr)95 void HcMonitorFree(void *addr)
96 {
97     if (!g_isInit) {
98         return;
99     }
100     g_mutex->lock(g_mutex);
101     map<void *, MemoryBlock>::iterator iter = gMemoryMap.find(addr);
102     if (iter != gMemoryMap.end()) {
103         g_mallocCount -= GetRealMallocSize(iter->second.size);
104         gMemoryMap.erase(iter);
105     } else {
106         cout << "############## Monitor Free error, addr is not exist!" << endl;
107     }
108     g_mutex->unlock(g_mutex);
109 }
110 
ReportMonitor(void)111 void ReportMonitor(void)
112 {
113     if (!g_isInit) {
114         return;
115     }
116     g_mutex->lock(g_mutex);
117     printf("\n############## Monitor Report ##############\nMemoryBlock Num: %zu\nMemory Used Size: %d\n"
118         "Memory Max Used Size: %d\nMemory Max Single Size: %d\n",
119         gMemoryMap.size(), g_mallocCount, g_maxCount, g_maxSingleCount);
120     for (map<void *, MemoryBlock>::iterator iter = gMemoryMap.begin(); iter != gMemoryMap.end(); ++iter) {
121         printf("\n############## Memory Block ##############\nMemoryBlock Id: %d\nMemoryBlock Size: %d\n"
122             "MemoryBlock Size: %d\nMemoryBlock Location: %s\n",
123             iter->second.id, iter->second.size, iter->second.realSize, iter->second.str.c_str());
124     }
125     g_mutex->unlock(g_mutex);
126 }
127 
IsMemoryLeak(void)128 bool IsMemoryLeak(void)
129 {
130     return g_mallocCount > 0;
131 }
132 
HcInitMallocMonitor(void)133 void HcInitMallocMonitor(void)
134 {
135     if (g_isInit) {
136         return;
137     }
138     g_isInit = true;
139     g_mutex = static_cast<HcMutex *>(malloc(sizeof(HcMutex)));
140     InitHcMutex(g_mutex);
141 }
142 
HcDestroyMallocMonitor(void)143 void HcDestroyMallocMonitor(void)
144 {
145     if (!g_isInit) {
146         return;
147     }
148     g_isInit = false;
149     g_mutex->lock(g_mutex);
150     gMemoryMap.clear();
151     g_mallocCount = 0;
152     g_maxCount = 0;
153     g_maxSingleCount = 0;
154     g_count = 0;
155     g_mutex->unlock(g_mutex);
156     DestroyHcMutex(g_mutex);
157     free(g_mutex);
158     g_mutex = NULL;
159 }
160