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 "tooling/client/domain/heapprofiler_client.h"
17 #include "tooling/client/session/session.h"
18
19 using Result = panda::ecmascript::tooling::Result;
20 namespace OHOS::ArkCompiler::Toolchain {
21 static constexpr int32_t SAMPLING_INTERVAL = 16384;
DispatcherCmd(const std::string & cmd,const std::string & arg)22 bool HeapProfilerClient::DispatcherCmd(const std::string &cmd, const std::string &arg)
23 {
24 path_ = arg;
25
26 std::map<std::string, std::function<int()>> dispatcherTable {
27 { "allocationtrack", std::bind(&HeapProfilerClient::AllocationTrackCommand, this)},
28 { "allocationtrack-stop", std::bind(&HeapProfilerClient::AllocationTrackStopCommand, this)},
29 { "heapdump", std::bind(&HeapProfilerClient::HeapDumpCommand, this)},
30 { "heapprofiler-enable", std::bind(&HeapProfilerClient::Enable, this)},
31 { "heapprofiler-disable", std::bind(&HeapProfilerClient::Disable, this)},
32 { "sampling", std::bind(&HeapProfilerClient::Samping, this)},
33 { "sampling-stop", std::bind(&HeapProfilerClient::SampingStop, this)},
34 { "collectgarbage", std::bind(&HeapProfilerClient::CollectGarbage, this)}
35 };
36
37 auto entry = dispatcherTable.find(cmd);
38 if (entry != dispatcherTable.end() && entry->second != nullptr) {
39 entry->second();
40 LOGI("DispatcherCmd reqStr1: %{public}s", cmd.c_str());
41 return true;
42 }
43
44 LOGI("unknown command: %{public}s", cmd.c_str());
45 return false;
46 }
47
HeapDumpCommand()48 int HeapProfilerClient::HeapDumpCommand()
49 {
50 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
51 uint32_t id = session->GetMessageId();
52
53 idEventMap_.emplace(id, HEAPDUMP);
54 std::unique_ptr<PtJson> request = PtJson::CreateObject();
55 request->Add("id", id);
56 request->Add("method", "HeapProfiler.takeHeapSnapshot");
57
58 std::unique_ptr<PtJson> params = PtJson::CreateObject();
59 params->Add("reportProgress", true);
60 params->Add("captureNumericValue", true);
61 params->Add("exposeInternals", false);
62 request->Add("params", params);
63
64 std::string message = request->Stringify();
65 if (session->ClientSendReq(message)) {
66 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
67 }
68 return 0;
69 }
70
AllocationTrackCommand()71 int HeapProfilerClient::AllocationTrackCommand()
72 {
73 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
74 uint32_t id = session->GetMessageId();
75
76 idEventMap_.emplace(id, ALLOCATION);
77 std::unique_ptr<PtJson> request = PtJson::CreateObject();
78 request->Add("id", id);
79 request->Add("method", "HeapProfiler.startTrackingHeapObjects");
80
81 std::unique_ptr<PtJson> params = PtJson::CreateObject();
82 params->Add("trackAllocations", true);
83 request->Add("params", params);
84
85 std::string message = request->Stringify();
86 if (session->ClientSendReq(message)) {
87 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
88 }
89 return 0;
90 }
91
AllocationTrackStopCommand()92 int HeapProfilerClient::AllocationTrackStopCommand()
93 {
94 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
95 uint32_t id = session->GetMessageId();
96
97 idEventMap_.emplace(id, ALLOCATION_STOP);
98 std::unique_ptr<PtJson> request = PtJson::CreateObject();
99 request->Add("id", id);
100 request->Add("method", "HeapProfiler.stopTrackingHeapObjects");
101
102 std::unique_ptr<PtJson> params = PtJson::CreateObject();
103 params->Add("reportProgress", true);
104 request->Add("params", params);
105
106 std::string message = request->Stringify();
107 if (session->ClientSendReq(message)) {
108 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
109 }
110 return 0;
111 }
112
Enable()113 int HeapProfilerClient::Enable()
114 {
115 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
116 uint32_t id = session->GetMessageId();
117
118 idEventMap_.emplace(id, ENABLE);
119 std::unique_ptr<PtJson> request = PtJson::CreateObject();
120 request->Add("id", id);
121 request->Add("method", "HeapProfiler.enable");
122
123 std::unique_ptr<PtJson> params = PtJson::CreateObject();
124 request->Add("params", params);
125
126 std::string message = request->Stringify();
127 if (session->ClientSendReq(message)) {
128 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
129 }
130 return 0;
131 }
132
Disable()133 int HeapProfilerClient::Disable()
134 {
135 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
136 uint32_t id = session->GetMessageId();
137
138 idEventMap_.emplace(id, DISABLE);
139 std::unique_ptr<PtJson> request = PtJson::CreateObject();
140 request->Add("id", id);
141 request->Add("method", "HeapProfiler.disable");
142
143 std::unique_ptr<PtJson> params = PtJson::CreateObject();
144 request->Add("params", params);
145
146 std::string message = request->Stringify();
147 if (session->ClientSendReq(message)) {
148 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
149 }
150 return 0;
151 }
152
Samping()153 int HeapProfilerClient::Samping()
154 {
155 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
156 uint32_t id = session->GetMessageId();
157
158 idEventMap_.emplace(id, SAMPLING);
159 std::unique_ptr<PtJson> request = PtJson::CreateObject();
160 request->Add("id", id);
161 request->Add("method", "HeapProfiler.startSampling");
162
163 std::unique_ptr<PtJson> params = PtJson::CreateObject();
164 params->Add("samplingInterval", SAMPLING_INTERVAL);
165 request->Add("params", params);
166
167 std::string message = request->Stringify();
168 if (session->ClientSendReq(message)) {
169 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
170 }
171 return 0;
172 }
173
SampingStop()174 int HeapProfilerClient::SampingStop()
175 {
176 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
177 uint32_t id = session->GetMessageId();
178
179 idEventMap_.emplace(id, SAMPLING_STOP);
180 std::unique_ptr<PtJson> request = PtJson::CreateObject();
181 request->Add("id", id);
182 request->Add("method", "HeapProfiler.stopSampling");
183
184 std::unique_ptr<PtJson> params = PtJson::CreateObject();
185 request->Add("params", params);
186
187 std::string message = request->Stringify();
188 if (session->ClientSendReq(message)) {
189 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
190 }
191 return 0;
192 }
193
CollectGarbage()194 int HeapProfilerClient::CollectGarbage()
195 {
196 Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
197 uint32_t id = session->GetMessageId();
198
199 idEventMap_.emplace(id, COLLECT_GARBAGE);
200 std::unique_ptr<PtJson> request = PtJson::CreateObject();
201 request->Add("id", id);
202 request->Add("method", "HeapProfiler.collectGarbage");
203
204 std::unique_ptr<PtJson> params = PtJson::CreateObject();
205 request->Add("params", params);
206
207 std::string message = request->Stringify();
208 if (session->ClientSendReq(message)) {
209 session->GetDomainManager().SetDomainById(id, "HeapProfiler");
210 }
211 return 0;
212 }
213
RecvReply(std::unique_ptr<PtJson> json)214 void HeapProfilerClient::RecvReply(std::unique_ptr<PtJson> json)
215 {
216 if (json == nullptr) {
217 LOGE("json parse error");
218 return;
219 }
220 if (!json->IsObject()) {
221 LOGE("json parse format error");
222 json->ReleaseRoot();
223 return;
224 }
225 std::unique_ptr<PtJson> result;
226 Result ret = json->GetObject("result", &result);
227 if (ret == Result::SUCCESS) {
228 SaveHeapsamplingData(std::move(result));
229 return;
230 }
231 std::string wholeMethod;
232 std::string method;
233 ret = json->GetString("method", &wholeMethod);
234 if (ret != Result::SUCCESS || wholeMethod.empty()) {
235 LOGE("find method error");
236 return;
237 }
238 std::string::size_type length = wholeMethod.length();
239 std::string::size_type indexPoint = 0;
240 indexPoint = wholeMethod.find_first_of('.', 0);
241 if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) {
242 return;
243 }
244 method = wholeMethod.substr(indexPoint + 1, length);
245 if (method == "lastSeenObjectId") {
246 isAllocationMsg_ = true;
247 }
248 std::unique_ptr<PtJson> params;
249 ret = json->GetObject("params", ¶ms);
250 if (ret != Result::SUCCESS) {
251 LOGE("find params error");
252 return;
253 }
254 std::string chunk;
255 ret = params->GetString("chunk", &chunk);
256 if (ret == Result::SUCCESS) {
257 SaveHeapSnapshotAndAllocationTrackData(chunk);
258 }
259 return;
260 }
261
SaveHeapSnapshotAndAllocationTrackData(const std::string & chunk)262 void HeapProfilerClient::SaveHeapSnapshotAndAllocationTrackData(const std::string &chunk)
263 {
264 std::string head = "{\"snapshot\":\n";
265 std::string heapFile;
266 if (!strncmp(chunk.c_str(), head.c_str(), head.length())) {
267 char date[16];
268 char time[16];
269 bool res = Utils::GetCurrentTime(date, time, sizeof(date));
270 if (!res) {
271 LOGE("arkdb: get time failed");
272 return;
273 }
274 if (isAllocationMsg_) {
275 heapFile = "Heap-" + std::to_string(sessionId_) + "-" + std::string(date) + "T" + std::string(time) +
276 ".heaptimeline";
277 fileName_ = path_ + heapFile;
278 std::cout << "heaptimeline file name is " << fileName_ << std::endl;
279 } else {
280 heapFile = "Heap-"+ std::to_string(sessionId_) + "-" + std::string(date) + "T" + std::string(time) +
281 ".heapsnapshot";
282 fileName_ = path_ + heapFile;
283 std::cout << "heapsnapshot file name is " << fileName_ << std::endl;
284 }
285 std::cout << ">>> ";
286 fflush(stdout);
287 }
288
289 std::string tail = "]\n}\n";
290 std::string subStr = chunk.substr(chunk.length() - tail.length(), chunk.length());
291 if (!strncmp(subStr.c_str(), tail.c_str(), tail.length())) {
292 isAllocationMsg_ = false;
293 }
294 WriteHeapProfilerForFile(fileName_, chunk);
295 return;
296 }
297
SaveHeapsamplingData(std::unique_ptr<PtJson> result)298 void HeapProfilerClient::SaveHeapsamplingData(std::unique_ptr<PtJson> result)
299 {
300 std::unique_ptr<PtJson> profile;
301 std::string heapFile;
302 Result ret = result->GetObject("profile", &profile);
303 if (ret != Result::SUCCESS) {
304 LOGE("arkdb: get profile failed");
305 return;
306 }
307 char date[16];
308 char time[16];
309 bool res = Utils::GetCurrentTime(date, time, sizeof(date));
310 if (!res) {
311 LOGE("arkdb: get time failed");
312 return;
313 }
314 heapFile = "Heap-" + std::to_string(sessionId_) + "-" + std::string(date) + "T" + std::string(time) +
315 ".heapprofile";
316 fileName_ = path_ + heapFile;
317 std::cout << "heapprofile file name is " << fileName_ << std::endl;
318 std::cout << ">>> ";
319 fflush(stdout);
320
321 WriteHeapProfilerForFile(fileName_, profile->Stringify());
322 return;
323 }
324
WriteHeapProfilerForFile(const std::string & fileName,const std::string & data)325 bool HeapProfilerClient::WriteHeapProfilerForFile(const std::string &fileName, const std::string &data)
326 {
327 std::ofstream ofs;
328 std::string realPath;
329 bool res = Utils::RealPath(fileName, realPath, false);
330 if (!res) {
331 LOGE("arkdb: path is not realpath!");
332 return false;
333 }
334 ofs.open(fileName.c_str(), std::ios::app);
335 if (!ofs.is_open()) {
336 LOGE("arkdb: file open error!");
337 return false;
338 }
339 size_t strSize = data.size();
340 ofs.write(data.c_str(), strSize);
341 ofs.close();
342 ofs.clear();
343 return true;
344 }
345 } // OHOS::ArkCompiler::Toolchain