• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/dynamic/client/domain/heapprofiler_client.h"
17 #include "tooling/dynamic/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", &params);
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