1 /*
2 * Copyright (c) 2021 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 "agent/heapprofiler_impl.h"
17
18 namespace panda::ecmascript::tooling {
19 static constexpr int32_t MILLI_TO_MICRO = 1000;
Dispatch(const DispatchRequest & request)20 void HeapProfilerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request)
21 {
22 static std::unordered_map<std::string, AgentHandler> dispatcherTable {
23 { "addInspectedHeapObject", &HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject },
24 { "collectGarbage", &HeapProfilerImpl::DispatcherImpl::CollectGarbage },
25 { "enable", &HeapProfilerImpl::DispatcherImpl::Enable },
26 { "disable", &HeapProfilerImpl::DispatcherImpl::Disable },
27 { "getHeapObjectId", &HeapProfilerImpl::DispatcherImpl::GetHeapObjectId },
28 { "getObjectByHeapObjectId", &HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId },
29 { "getSamplingProfile", &HeapProfilerImpl::DispatcherImpl::GetSamplingProfile },
30 { "startSampling", &HeapProfilerImpl::DispatcherImpl::StartSampling },
31 { "startTrackingHeapObjects", &HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects },
32 { "stopSampling", &HeapProfilerImpl::DispatcherImpl::StopSampling },
33 { "stopTrackingHeapObjects", &HeapProfilerImpl::DispatcherImpl::StopTrackingHeapObjects },
34 { "takeHeapSnapshot", &HeapProfilerImpl::DispatcherImpl::TakeHeapSnapshot }
35 };
36
37 const std::string &method = request.GetMethod();
38 LOG_DEBUGGER(DEBUG) << "dispatch [" << method << "] to HeapProfilerImpl";
39 auto entry = dispatcherTable.find(method);
40 if (entry != dispatcherTable.end() && entry->second != nullptr) {
41 (this->*(entry->second))(request);
42 } else {
43 SendResponse(request, DispatchResponse::Fail("Unknown method: " + method));
44 }
45 }
46
AddInspectedHeapObject(const DispatchRequest & request)47 void HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject(const DispatchRequest &request)
48 {
49 std::unique_ptr<AddInspectedHeapObjectParams> params = AddInspectedHeapObjectParams::Create(request.GetParams());
50 if (params == nullptr) {
51 SendResponse(request, DispatchResponse::Fail("wrong params"));
52 return;
53 }
54 DispatchResponse response = heapprofiler_->AddInspectedHeapObject(*params);
55 SendResponse(request, response);
56 }
57
CollectGarbage(const DispatchRequest & request)58 void HeapProfilerImpl::DispatcherImpl::CollectGarbage(const DispatchRequest &request)
59 {
60 DispatchResponse response = heapprofiler_->CollectGarbage();
61 SendResponse(request, response);
62 }
63
Enable(const DispatchRequest & request)64 void HeapProfilerImpl::DispatcherImpl::Enable(const DispatchRequest &request)
65 {
66 DispatchResponse response = heapprofiler_->Enable();
67 SendResponse(request, response);
68 }
69
Disable(const DispatchRequest & request)70 void HeapProfilerImpl::DispatcherImpl::Disable(const DispatchRequest &request)
71 {
72 DispatchResponse response = heapprofiler_->Disable();
73 SendResponse(request, response);
74 }
75
GetHeapObjectId(const DispatchRequest & request)76 void HeapProfilerImpl::DispatcherImpl::GetHeapObjectId(const DispatchRequest &request)
77 {
78 std::unique_ptr<GetHeapObjectIdParams> params = GetHeapObjectIdParams::Create(request.GetParams());
79 if (params == nullptr) {
80 SendResponse(request, DispatchResponse::Fail("wrong params"));
81 return;
82 }
83
84 HeapSnapshotObjectId objectId;
85 DispatchResponse response = heapprofiler_->GetHeapObjectId(*params, &objectId);
86 GetHeapObjectIdReturns result(std::move(objectId));
87 SendResponse(request, response, result);
88 }
89
GetObjectByHeapObjectId(const DispatchRequest & request)90 void HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId(const DispatchRequest &request)
91 {
92 std::unique_ptr<GetObjectByHeapObjectIdParams> params = GetObjectByHeapObjectIdParams::Create(request.GetParams());
93 if (params == nullptr) {
94 SendResponse(request, DispatchResponse::Fail("wrong params"));
95 return;
96 }
97
98 std::unique_ptr<RemoteObject> remoteObjectResult;
99 DispatchResponse response = heapprofiler_->GetObjectByHeapObjectId(*params, &remoteObjectResult);
100 if (remoteObjectResult == nullptr) {
101 SendResponse(request, response);
102 return;
103 }
104
105 GetObjectByHeapObjectIdReturns result(std::move(remoteObjectResult));
106 SendResponse(request, response, result);
107 }
108
GetSamplingProfile(const DispatchRequest & request)109 void HeapProfilerImpl::DispatcherImpl::GetSamplingProfile(const DispatchRequest &request)
110 {
111 std::unique_ptr<SamplingHeapProfile> profile;
112 DispatchResponse response = heapprofiler_->GetSamplingProfile(&profile);
113 if (profile == nullptr) {
114 SendResponse(request, response);
115 return;
116 }
117
118 // The return value type of GetSamplingProfile is the same as of StopSampling.
119 StopSamplingReturns result(std::move(profile));
120 SendResponse(request, response, result);
121 }
122
StartSampling(const DispatchRequest & request)123 void HeapProfilerImpl::DispatcherImpl::StartSampling(const DispatchRequest &request)
124 {
125 std::unique_ptr<StartSamplingParams> params = StartSamplingParams::Create(request.GetParams());
126 if (params == nullptr) {
127 SendResponse(request, DispatchResponse::Fail("wrong params"));
128 return;
129 }
130 DispatchResponse response = heapprofiler_->StartSampling(*params);
131 SendResponse(request, response);
132 }
133
StartTrackingHeapObjects(const DispatchRequest & request)134 void HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects(const DispatchRequest &request)
135 {
136 std::unique_ptr<StartTrackingHeapObjectsParams> params =
137 StartTrackingHeapObjectsParams::Create(request.GetParams());
138 if (params == nullptr) {
139 SendResponse(request, DispatchResponse::Fail("wrong params"));
140 return;
141 }
142 DispatchResponse response = heapprofiler_->StartTrackingHeapObjects(*params);
143 SendResponse(request, response);
144 }
145
146
StopSampling(const DispatchRequest & request)147 void HeapProfilerImpl::DispatcherImpl::StopSampling(const DispatchRequest &request)
148 {
149 std::unique_ptr<SamplingHeapProfile> profile;
150 DispatchResponse response = heapprofiler_->StopSampling(&profile);
151 if (profile == nullptr) {
152 SendResponse(request, response);
153 return;
154 }
155
156 StopSamplingReturns result(std::move(profile));
157 SendResponse(request, response, result);
158 }
159
StopTrackingHeapObjects(const DispatchRequest & request)160 void HeapProfilerImpl::DispatcherImpl::StopTrackingHeapObjects(const DispatchRequest &request)
161 {
162 std::unique_ptr<StopTrackingHeapObjectsParams> params = StopTrackingHeapObjectsParams::Create(request.GetParams());
163 if (params == nullptr) {
164 SendResponse(request, DispatchResponse::Fail("wrong params"));
165 return;
166 }
167 DispatchResponse response = heapprofiler_->StopTrackingHeapObjects(*params);
168 SendResponse(request, response);
169 }
170
TakeHeapSnapshot(const DispatchRequest & request)171 void HeapProfilerImpl::DispatcherImpl::TakeHeapSnapshot(const DispatchRequest &request)
172 {
173 std::unique_ptr<StopTrackingHeapObjectsParams> params = StopTrackingHeapObjectsParams::Create(request.GetParams());
174 if (params == nullptr) {
175 SendResponse(request, DispatchResponse::Fail("wrong params"));
176 return;
177 }
178 DispatchResponse response = heapprofiler_->TakeHeapSnapshot(*params);
179 SendResponse(request, response);
180 }
181
AllowNotify() const182 bool HeapProfilerImpl::Frontend::AllowNotify() const
183 {
184 return channel_ != nullptr;
185 }
186
AddHeapSnapshotChunk(char * data,int32_t size)187 void HeapProfilerImpl::Frontend::AddHeapSnapshotChunk(char *data, int32_t size)
188 {
189 if (!AllowNotify()) {
190 return;
191 }
192
193 tooling::AddHeapSnapshotChunk addHeapSnapshotChunk;
194 addHeapSnapshotChunk.GetChunk().resize(size);
195 for (int32_t i = 0; i < size; ++i) {
196 addHeapSnapshotChunk.GetChunk()[i] = data[i];
197 }
198
199 channel_->SendNotification(addHeapSnapshotChunk);
200 }
201
ReportHeapSnapshotProgress(int32_t done,int32_t total)202 void HeapProfilerImpl::Frontend::ReportHeapSnapshotProgress(int32_t done, int32_t total)
203 {
204 if (!AllowNotify()) {
205 return;
206 }
207
208 tooling::ReportHeapSnapshotProgress reportHeapSnapshotProgress;
209 reportHeapSnapshotProgress.SetDone(done).SetTotal(total);
210 if (done >= total) {
211 reportHeapSnapshotProgress.SetFinished(true);
212 }
213 channel_->SendNotification(reportHeapSnapshotProgress);
214 }
215
HeapStatsUpdate(HeapStat * updateData,int32_t count)216 void HeapProfilerImpl::Frontend::HeapStatsUpdate(HeapStat* updateData, int32_t count)
217 {
218 if (!AllowNotify()) {
219 return;
220 }
221 std::vector<int32_t> statsDiff;
222 for (int32_t i = 0; i < count; ++i) {
223 statsDiff.emplace_back(updateData[i].index_);
224 statsDiff.emplace_back(updateData[i].count_);
225 statsDiff.emplace_back(updateData[i].size_);
226 }
227 tooling::HeapStatsUpdate heapStatsUpdate;
228 heapStatsUpdate.SetStatsUpdate(std::move(statsDiff));
229 channel_->SendNotification(heapStatsUpdate);
230 }
231
LastSeenObjectId(int32_t lastSeenObjectId,int64_t timeStampUs)232 void HeapProfilerImpl::Frontend::LastSeenObjectId(int32_t lastSeenObjectId, int64_t timeStampUs)
233 {
234 if (!AllowNotify()) {
235 return;
236 }
237
238 tooling::LastSeenObjectId lastSeenObjectIdEvent;
239 lastSeenObjectIdEvent.SetLastSeenObjectId(lastSeenObjectId);
240 const int THOUSAND = 1000;
241 double timestampMS = static_cast<double>(timeStampUs) / THOUSAND;
242 lastSeenObjectIdEvent.SetTimestamp(timestampMS);
243 channel_->SendNotification(lastSeenObjectIdEvent);
244 }
245
ResetProfiles()246 void HeapProfilerImpl::Frontend::ResetProfiles()
247 {
248 if (!AllowNotify()) {
249 return;
250 }
251 }
252
AddInspectedHeapObject(const AddInspectedHeapObjectParams & params)253 DispatchResponse HeapProfilerImpl::AddInspectedHeapObject([[maybe_unused]] const AddInspectedHeapObjectParams ¶ms)
254 {
255 return DispatchResponse::Fail("AddInspectedHeapObject not support now");
256 }
257
CollectGarbage()258 DispatchResponse HeapProfilerImpl::CollectGarbage()
259 {
260 panda::JSNApi::TriggerGC(vm_, panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
261 panda::JSNApi::TriggerGC(vm_, panda::JSNApi::TRIGGER_GC_TYPE::OLD_GC);
262 return DispatchResponse::Ok();
263 }
264
Enable()265 DispatchResponse HeapProfilerImpl::Enable()
266 {
267 return DispatchResponse::Ok();
268 }
269
Disable()270 DispatchResponse HeapProfilerImpl::Disable()
271 {
272 return DispatchResponse::Ok();
273 }
274
GetHeapObjectId(const GetHeapObjectIdParams & params,HeapSnapshotObjectId * objectId)275 DispatchResponse HeapProfilerImpl::GetHeapObjectId([[maybe_unused]] const GetHeapObjectIdParams ¶ms,
276 HeapSnapshotObjectId *objectId)
277 {
278 ASSERT(objectId != nullptr);
279 *objectId = 0;
280 return DispatchResponse::Fail("GetHeapObjectId not support now");
281 }
282
GetObjectByHeapObjectId(const GetObjectByHeapObjectIdParams & params,std::unique_ptr<RemoteObject> * remoteObjectResult)283 DispatchResponse HeapProfilerImpl::GetObjectByHeapObjectId([[maybe_unused]] const GetObjectByHeapObjectIdParams ¶ms,
284 [[maybe_unused]] std::unique_ptr<RemoteObject> *remoteObjectResult)
285 {
286 return DispatchResponse::Fail("GetObjectByHeapObjectId not support now");
287 }
288
GetSamplingProfile(std::unique_ptr<SamplingHeapProfile> * profile)289 DispatchResponse HeapProfilerImpl::GetSamplingProfile([[maybe_unused]]std::unique_ptr<SamplingHeapProfile> *profile)
290 {
291 return DispatchResponse::Fail("GetSamplingProfile not support now");
292 }
293
StartSampling(const StartSamplingParams & params)294 DispatchResponse HeapProfilerImpl::StartSampling([[maybe_unused]]const StartSamplingParams ¶ms)
295 {
296 return DispatchResponse::Fail("StartSampling not support now");
297 }
298
StartTrackingHeapObjects(const StartTrackingHeapObjectsParams & params)299 DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects(const StartTrackingHeapObjectsParams ¶ms)
300 {
301 bool traceAllocation = params.GetTrackAllocations();
302 bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_, traceAllocation, false);
303
304 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm_->GetLoop());
305 uv_timer_init(loop, &handle_);
306 handle_.data = this;
307 uv_timer_start(&handle_, HeapTrackingCallback, 0, INTERVAL * MILLI_TO_MICRO);
308
309 uv_work_t *work = new uv_work_t;
310 uv_queue_work(loop, work, [](uv_work_t *) { }, [](uv_work_t *work, int32_t) { delete work; });
311
312 if (result) {
313 return DispatchResponse::Ok();
314 } else {
315 return DispatchResponse::Fail("StartHeapTracking fail");
316 }
317 }
318
HeapTrackingCallback(uv_timer_t * handle)319 void HeapProfilerImpl::HeapTrackingCallback(uv_timer_t* handle)
320 {
321 HeapProfilerImpl *heapProfilerImpl = static_cast<HeapProfilerImpl *>(handle->data);
322 if (heapProfilerImpl == nullptr) {
323 return;
324 }
325 panda::DFXJSNApi::UpdateHeapTracking(heapProfilerImpl->vm_, &(heapProfilerImpl->stream_));
326 }
327
StopSampling(std::unique_ptr<SamplingHeapProfile> * profile)328 DispatchResponse HeapProfilerImpl::StopSampling([[maybe_unused]]std::unique_ptr<SamplingHeapProfile> *profile)
329 {
330 return DispatchResponse::Fail("StopSampling not support now.");
331 }
332
StopTrackingHeapObjects(const StopTrackingHeapObjectsParams & params)333 DispatchResponse HeapProfilerImpl::StopTrackingHeapObjects(const StopTrackingHeapObjectsParams ¶ms)
334 {
335 bool result = false;
336 if (params.GetReportProgress()) {
337 HeapProfilerProgress progress(&frontend_);
338 result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, &progress, false);
339 } else {
340 result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, nullptr, false);
341 }
342 uv_timer_stop(&handle_);
343 if (result) {
344 return DispatchResponse::Ok();
345 } else {
346 return DispatchResponse::Fail("StopHeapTracking fail");
347 }
348 }
349
TakeHeapSnapshot(const StopTrackingHeapObjectsParams & params)350 DispatchResponse HeapProfilerImpl::TakeHeapSnapshot(const StopTrackingHeapObjectsParams ¶ms)
351 {
352 if (params.GetReportProgress()) {
353 HeapProfilerProgress progress(&frontend_);
354 panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, &progress, true);
355 } else {
356 panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, nullptr, true);
357 }
358 return DispatchResponse::Ok();
359 }
360 } // namespace panda::ecmascript::tooling
361