• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }