1 /*
2 * Copyright (C) 2022 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 "gmemdfx.h"
17 #include <unordered_map>
18 #include <vector>
19 #include <hilog/log.h>
20 #include <unistd.h>
21 #include "gmemdfxdump.h"
22 #include "dfx_dump_catcher.h"
23 #include "param_wrapper.h"
24 #include "string_ex.h"
25
26 #undef LOG_DOMAIN
27 #define LOG_DOMAIN 0xD002B00
28
29 #define __LOG(func, fmt, args...) \
30 do { \
31 (void)func(LABEL, "{%{public}s():%{public}d} " fmt, __FUNCTION__, __LINE__, ##args); \
32 } while (0)
33
34 #define LOGE(fmt, ...) __LOG(::OHOS::HiviewDFX::HiLog::Error, fmt, ##__VA_ARGS__)
35
36 #define POINTER_MASK 0x00FFFFFF
37 #define FAKE_POINTER(addr) (POINTER_MASK & reinterpret_cast<uintptr_t>(addr))
38
39 struct MemInfo {
40 uint64_t count = 0;
41 uint64_t size = 0;
42 std::string str;
43 intptr_t mem;
44 };
45
46 struct PoolInfo {
47 uint64_t count = 0;
48 uint64_t size = 0;
49 uint64_t alignment = 0;
50 uint64_t lastTid = 0;
51 intptr_t mem;
52 };
53
54 namespace {
55 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVGlibMemDfx"};
56 static std::unordered_map<void *, MemInfo> memMap;
57 static std::unordered_map<void *, PoolInfo> poolMap;
58 static uint64_t memCount = 0;
59 static uint64_t poolCount = 0;
60 static std::mutex mutex;
61 static bool enableDump = false;
62 static unsigned int dumpSize = 0;
63 static unsigned int dumpStart = 0;
64 static unsigned int dumpCount = 0;
65 static bool dumpOpen = false;
66 }
67
GMemPoolAllocDfx(void * mem,unsigned int alignment,unsigned int size)68 void GMemPoolAllocDfx(void *mem, unsigned int alignment, unsigned int size)
69 {
70 std::lock_guard<std::mutex> lock(mutex);
71 if (!dumpOpen || mem == nullptr) {
72 return;
73 }
74 if (poolMap.find(mem) != poolMap.end()) {
75 LOGE("the mem 0x%{public}06" PRIXPTR " is already allocated", FAKE_POINTER(mem));
76 return;
77 }
78
79 poolMap[mem] = {poolCount++, size, alignment, gettid(), (intptr_t)mem};
80 }
81
GMemPoolFreeDfx(void * mem)82 void GMemPoolFreeDfx(void *mem)
83 {
84 std::lock_guard<std::mutex> lock(mutex);
85 if (!dumpOpen || mem == nullptr) {
86 return;
87 }
88 if (mem != nullptr && poolMap.erase(mem) == 0) {
89 LOGE("the mem 0x%{public}06" PRIXPTR " is already free", FAKE_POINTER(mem));
90 }
91 }
92
GMemAllocDfx(void * mem,unsigned int size)93 void GMemAllocDfx(void *mem, unsigned int size)
94 {
95 std::lock_guard<std::mutex> lock(mutex);
96 if (!dumpOpen || mem == nullptr) {
97 return;
98 }
99 if (memMap.find(mem) != memMap.end()) {
100 LOGE("the mem 0x%{public}06" PRIXPTR " is already allocated", FAKE_POINTER(mem));
101 return;
102 }
103 std::string str;
104 if (enableDump && size == dumpSize && (memCount - dumpStart) % dumpCount == 0) {
105 OHOS::HiviewDFX::DfxDumpCatcher dumpLog;
106 bool ret = dumpLog.DumpCatch(getpid(), gettid(), str);
107 if (!ret) {
108 LOGE("dump error");
109 }
110 }
111
112 memMap[mem] = {memCount++, size, str, (intptr_t)mem};
113 }
114
GChainMemFreeDfx(void * mem_chain,unsigned long next_offset)115 void GChainMemFreeDfx(void *mem_chain, unsigned long next_offset)
116 {
117 std::lock_guard<std::mutex> lock(mutex);
118 if (!dumpOpen || mem_chain == nullptr) {
119 return;
120 }
121 void *next = mem_chain;
122 while (next) {
123 uint8_t *current = (uint8_t *)next;
124 next = *(void **)(current + next_offset);
125 if (current != nullptr && memMap.erase(current) == 0) {
126 LOGE("the mem 0x%{public}06" PRIXPTR " is already free", FAKE_POINTER(current));
127 }
128 }
129 }
130
GMemFreeDfx(void * mem)131 void GMemFreeDfx(void *mem)
132 {
133 std::lock_guard<std::mutex> lock(mutex);
134 if (!dumpOpen || mem == nullptr) {
135 return;
136 }
137 if (mem != nullptr && memMap.erase(mem) == 0) {
138 LOGE("the mem 0x%{public}06" PRIXPTR " is already free", FAKE_POINTER(mem));
139 }
140 }
141
InitParameter()142 void InitParameter()
143 {
144 std::string dumpSizeStr;
145 std::string dumpStartStr;
146 std::string dumpCountStr;
147 std::string dumpOpenStr;
148 int32_t size;
149 int32_t start;
150 int32_t count;
151 int32_t res = OHOS::system::GetStringParameter("sys.media.dump.mem.size", dumpSizeStr, "");
152 if (res == 0 && !dumpSizeStr.empty()) {
153 OHOS::StrToInt(dumpSizeStr, size);
154 dumpSize = size;
155 enableDump = dumpSize == 0 ? false :true;
156 } else {
157 enableDump = false;
158 }
159 res = OHOS::system::GetStringParameter("sys.media.dump.mem.start", dumpStartStr, "");
160 if (res == 0 && !dumpStartStr.empty()) {
161 OHOS::StrToInt(dumpStartStr, start);
162 dumpStart = start;
163 } else {
164 dumpStart = 0;
165 }
166 res = OHOS::system::GetStringParameter("sys.media.dump.mem.count", dumpCountStr, "");
167 if (res == 0 && !dumpCountStr.empty()) {
168 OHOS::StrToInt(dumpCountStr, count);
169 dumpCount = count;
170 } else {
171 dumpCount = 1;
172 }
173 res = OHOS::system::GetStringParameter("sys.media.dump.mem.open", dumpOpenStr, "");
174 if (res == 0 && !dumpOpenStr.empty()) {
175 dumpOpen = dumpOpenStr == "TRUE" ? true : false;
176 } else {
177 dumpOpen = false;
178 }
179 }
180
GetGMemDump(std::string & str)181 void GetGMemDump(std::string &str)
182 {
183 std::unordered_map<void *, MemInfo> memMapCopy;
184 {
185 std::lock_guard<std::mutex> lock(mutex);
186 InitParameter();
187 memMapCopy = memMap;
188 }
189 std::vector<std::pair<void *, MemInfo>> memInfoVec(memMapCopy.begin(), memMapCopy.end());
190 std::sort(memInfoVec.begin(), memInfoVec.end(), [&](auto &left, auto &right) {
191 return left.second.count < right.second.count;
192 });
193 for (auto iter = memInfoVec.begin(); iter != memInfoVec.end(); iter++) {
194 str += "count:";
195 str += std::to_string(iter->second.count) + ";";
196 str += "size:";
197 str += std::to_string(iter->second.size) + "\n";
198 str += iter->second.str + "\n";
199 }
200 }
201
GetGMemPoolDump(std::string & str)202 void GetGMemPoolDump(std::string &str)
203 {
204 std::unordered_map<void *, PoolInfo> poolMapCopy;
205 {
206 std::lock_guard<std::mutex> lock(mutex);
207 InitParameter();
208 poolMapCopy = poolMap;
209 }
210 std::vector<std::pair<void *, PoolInfo>> poolInfoVec(poolMapCopy.begin(), poolMapCopy.end());
211 std::sort(poolInfoVec.begin(), poolInfoVec.end(), [&](auto &left, auto &right) {
212 return left.second.count < right.second.count;
213 });
214 for (auto iter = poolInfoVec.begin(); iter != poolInfoVec.end(); iter++) {
215 str += "count:";
216 str += std::to_string(iter->second.count) + ";";
217 str += "size:";
218 str += std::to_string(iter->second.size) + "\n";
219 str += "alignment:";
220 str += std::to_string(iter->second.alignment) + "\n";
221 str += "lastTid:";
222 str += std::to_string(iter->second.lastTid) + "\n";
223 }
224 }