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;
20 static constexpr double INTERVAL = 0.2;
Dispatch(const DispatchRequest & request)21 void HeapProfilerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request)
22 {
23 static std::unordered_map<std::string, AgentHandler> dispatcherTable {
24 { "addInspectedHeapObject", &HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject },
25 { "collectGarbage", &HeapProfilerImpl::DispatcherImpl::CollectGarbage },
26 { "enable", &HeapProfilerImpl::DispatcherImpl::Enable },
27 { "disable", &HeapProfilerImpl::DispatcherImpl::Disable },
28 { "getHeapObjectId", &HeapProfilerImpl::DispatcherImpl::GetHeapObjectId },
29 { "getObjectByHeapObjectId", &HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId },
30 { "getSamplingProfile", &HeapProfilerImpl::DispatcherImpl::GetSamplingProfile },
31 { "startSampling", &HeapProfilerImpl::DispatcherImpl::StartSampling },
32 { "startTrackingHeapObjects", &HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects },
33 { "stopSampling", &HeapProfilerImpl::DispatcherImpl::StopSampling },
34 { "stopTrackingHeapObjects", &HeapProfilerImpl::DispatcherImpl::StopTrackingHeapObjects },
35 { "takeHeapSnapshot", &HeapProfilerImpl::DispatcherImpl::TakeHeapSnapshot }
36 };
37
38 const std::string &method = request.GetMethod();
39 LOG_DEBUGGER(DEBUG) << "dispatch [" << method << "] to HeapProfilerImpl";
40 auto entry = dispatcherTable.find(method);
41 if (entry != dispatcherTable.end() && entry->second != nullptr) {
42 (this->*(entry->second))(request);
43 } else {
44 SendResponse(request, DispatchResponse::Fail("Unknown method: " + method));
45 }
46 }
47
AddInspectedHeapObject(const DispatchRequest & request)48 void HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject(const DispatchRequest &request)
49 {
50 std::unique_ptr<AddInspectedHeapObjectParams> params = AddInspectedHeapObjectParams::Create(request.GetParams());
51 if (params == nullptr) {
52 SendResponse(request, DispatchResponse::Fail("wrong params"));
53 return;
54 }
55 DispatchResponse response = heapprofiler_->AddInspectedHeapObject(*params);
56 SendResponse(request, response);
57 }
58
CollectGarbage(const DispatchRequest & request)59 void HeapProfilerImpl::DispatcherImpl::CollectGarbage(const DispatchRequest &request)
60 {
61 DispatchResponse response = heapprofiler_->CollectGarbage();
62 SendResponse(request, response);
63 }
64
Enable(const DispatchRequest & request)65 void HeapProfilerImpl::DispatcherImpl::Enable(const DispatchRequest &request)
66 {
67 DispatchResponse response = heapprofiler_->Enable();
68 SendResponse(request, response);
69 }
70
Disable(const DispatchRequest & request)71 void HeapProfilerImpl::DispatcherImpl::Disable(const DispatchRequest &request)
72 {
73 DispatchResponse response = heapprofiler_->Disable();
74 SendResponse(request, response);
75 }
76
GetHeapObjectId(const DispatchRequest & request)77 void HeapProfilerImpl::DispatcherImpl::GetHeapObjectId(const DispatchRequest &request)
78 {
79 std::unique_ptr<GetHeapObjectIdParams> params = GetHeapObjectIdParams::Create(request.GetParams());
80 if (params == nullptr) {
81 SendResponse(request, DispatchResponse::Fail("wrong params"));
82 return;
83 }
84
85 HeapSnapshotObjectId objectId;
86 DispatchResponse response = heapprofiler_->GetHeapObjectId(*params, &objectId);
87 GetHeapObjectIdReturns result(std::move(objectId));
88 SendResponse(request, response, result);
89 }
90
GetObjectByHeapObjectId(const DispatchRequest & request)91 void HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId(const DispatchRequest &request)
92 {
93 std::unique_ptr<GetObjectByHeapObjectIdParams> params = GetObjectByHeapObjectIdParams::Create(request.GetParams());
94 if (params == nullptr) {
95 SendResponse(request, DispatchResponse::Fail("wrong params"));
96 return;
97 }
98
99 std::unique_ptr<RemoteObject> remoteObjectResult;
100 DispatchResponse response = heapprofiler_->GetObjectByHeapObjectId(*params, &remoteObjectResult);
101 if (remoteObjectResult == nullptr) {
102 SendResponse(request, response);
103 return;
104 }
105
106 GetObjectByHeapObjectIdReturns result(std::move(remoteObjectResult));
107 SendResponse(request, response, result);
108 }
109
GetSamplingProfile(const DispatchRequest & request)110 void HeapProfilerImpl::DispatcherImpl::GetSamplingProfile(const DispatchRequest &request)
111 {
112 std::unique_ptr<SamplingHeapProfile> profile;
113 DispatchResponse response = heapprofiler_->GetSamplingProfile(&profile);
114 if (profile == nullptr) {
115 SendResponse(request, response);
116 return;
117 }
118
119 // The return value type of GetSamplingProfile is the same as of StopSampling.
120 StopSamplingReturns result(std::move(profile));
121 SendResponse(request, response, result);
122 }
123
StartSampling(const DispatchRequest & request)124 void HeapProfilerImpl::DispatcherImpl::StartSampling(const DispatchRequest &request)
125 {
126 std::unique_ptr<StartSamplingParams> params = StartSamplingParams::Create(request.GetParams());
127 if (params == nullptr) {
128 SendResponse(request, DispatchResponse::Fail("wrong params"));
129 return;
130 }
131 DispatchResponse response = heapprofiler_->StartSampling(*params);
132 SendResponse(request, response);
133 }
134
StopSampling(const DispatchRequest & request)135 void HeapProfilerImpl::DispatcherImpl::StopSampling(const DispatchRequest &request)
136 {
137 std::unique_ptr<SamplingHeapProfile> profile;
138 DispatchResponse response = heapprofiler_->StopSampling(&profile);
139 if (profile == nullptr) {
140 SendResponse(request, response);
141 return;
142 }
143
144 StopSamplingReturns result(std::move(profile));
145 SendResponse(request, response, result);
146 }
147
StartTrackingHeapObjects(const DispatchRequest & request)148 void HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects(const DispatchRequest &request)
149 {
150 std::unique_ptr<StartTrackingHeapObjectsParams> params =
151 StartTrackingHeapObjectsParams::Create(request.GetParams());
152 if (params == nullptr) {
153 SendResponse(request, DispatchResponse::Fail("wrong params"));
154 return;
155 }
156 DispatchResponse response = heapprofiler_->StartTrackingHeapObjects(*params);
157 SendResponse(request, response);
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 panda::DFXJSNApi::DestroyHeapProfiler(vm_);
273 return DispatchResponse::Ok();
274 }
275
GetHeapObjectId(const GetHeapObjectIdParams & params,HeapSnapshotObjectId * objectId)276 DispatchResponse HeapProfilerImpl::GetHeapObjectId([[maybe_unused]] const GetHeapObjectIdParams ¶ms,
277 HeapSnapshotObjectId *objectId)
278 {
279 ASSERT(objectId != nullptr);
280 *objectId = 0;
281 return DispatchResponse::Fail("GetHeapObjectId not support now");
282 }
283
GetObjectByHeapObjectId(const GetObjectByHeapObjectIdParams & params,std::unique_ptr<RemoteObject> * remoteObjectResult)284 DispatchResponse HeapProfilerImpl::GetObjectByHeapObjectId([[maybe_unused]] const GetObjectByHeapObjectIdParams ¶ms,
285 [[maybe_unused]] std::unique_ptr<RemoteObject> *remoteObjectResult)
286 {
287 return DispatchResponse::Fail("GetObjectByHeapObjectId not support now");
288 }
289
GetSamplingProfile(std::unique_ptr<SamplingHeapProfile> * profile)290 DispatchResponse HeapProfilerImpl::GetSamplingProfile([[maybe_unused]] std::unique_ptr<SamplingHeapProfile> *profile)
291 {
292 auto samplingInfo = panda::DFXJSNApi::GetAllocationProfile(vm_);
293 if (samplingInfo == nullptr) {
294 return DispatchResponse::Fail("GetSamplingProfile fail");
295 }
296 *profile = SamplingHeapProfile::FromSamplingInfo(std::move(samplingInfo));
297 return DispatchResponse::Ok();
298 }
299
StartSampling(const StartSamplingParams & params)300 DispatchResponse HeapProfilerImpl::StartSampling([[maybe_unused]] const StartSamplingParams ¶ms)
301 {
302 uint64_t samplingInterval = static_cast<uint64_t>(params.GetSamplingInterval());
303 bool result = panda::DFXJSNApi::StartSampling(vm_, samplingInterval);
304 if (result) {
305 return DispatchResponse::Ok();
306 }
307 return DispatchResponse::Fail("StartSampling fail");
308 }
309
StopSampling(std::unique_ptr<SamplingHeapProfile> * profile)310 DispatchResponse HeapProfilerImpl::StopSampling([[maybe_unused]] std::unique_ptr<SamplingHeapProfile> *profile)
311 {
312 DispatchResponse samplingProfile = GetSamplingProfile(profile);
313 if (samplingProfile.IsOk()) {
314 panda::DFXJSNApi::StopSampling(vm_);
315 return DispatchResponse::Ok();
316 }
317 return DispatchResponse::Fail("StopSampling fail");
318 }
319
StartTrackingHeapObjects(const StartTrackingHeapObjectsParams & params)320 DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects(const StartTrackingHeapObjectsParams ¶ms)
321 {
322 if (uv_is_active(reinterpret_cast<uv_handle_t*>(&handle_))) {
323 return DispatchResponse::Ok();
324 }
325 bool traceAllocation = params.GetTrackAllocations();
326 bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_, traceAllocation, false);
327
328 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm_->GetLoop());
329 if (loop == nullptr) {
330 return DispatchResponse::Fail("Loop is nullptr");
331 }
332 uv_timer_init(loop, &handle_);
333 handle_.data = this;
334 uv_timer_start(&handle_, HeapTrackingCallback, 0, INTERVAL * MILLI_TO_MICRO);
335
336 uv_work_t *work = new uv_work_t;
337 uv_queue_work(loop, work, [](uv_work_t *) { }, [](uv_work_t *work, int32_t) { delete work; });
338
339 if (result) {
340 return DispatchResponse::Ok();
341 } else {
342 return DispatchResponse::Fail("StartHeapTracking fail");
343 }
344 }
345
HeapTrackingCallback(uv_timer_t * handle)346 void HeapProfilerImpl::HeapTrackingCallback(uv_timer_t* handle)
347 {
348 HeapProfilerImpl *heapProfilerImpl = static_cast<HeapProfilerImpl *>(handle->data);
349 if (heapProfilerImpl == nullptr) {
350 return;
351 }
352 panda::DFXJSNApi::UpdateHeapTracking(heapProfilerImpl->vm_, &(heapProfilerImpl->stream_));
353 }
354
StopTrackingHeapObjects(const StopTrackingHeapObjectsParams & params)355 DispatchResponse HeapProfilerImpl::StopTrackingHeapObjects(const StopTrackingHeapObjectsParams ¶ms)
356 {
357 uv_timer_stop(&handle_);
358 bool result = false;
359 if (params.GetReportProgress()) {
360 HeapProfilerProgress progress(&frontend_);
361 result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, &progress, false);
362 } else {
363 result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, nullptr, false);
364 }
365 if (result) {
366 return DispatchResponse::Ok();
367 } else {
368 return DispatchResponse::Fail("StopHeapTracking fail");
369 }
370 }
371
TakeHeapSnapshot(const StopTrackingHeapObjectsParams & params)372 DispatchResponse HeapProfilerImpl::TakeHeapSnapshot(const StopTrackingHeapObjectsParams ¶ms)
373 {
374 bool captureNumericValue = params.GetCaptureNumericValue();
375 if (params.GetReportProgress()) {
376 HeapProfilerProgress progress(&frontend_);
377 panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, &progress, true, false, captureNumericValue);
378 } else {
379 panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, nullptr, true, false, captureNumericValue);
380 }
381 return DispatchResponse::Ok();
382 }
383 } // namespace panda::ecmascript::tooling
384