• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
21 // Whenever adding a new protocol which is not a standard CDP protocol,
22 // must add its methodName to the heapProfilerProtocolList
InitializeExtendedProtocolsList()23 void HeapProfilerImpl::InitializeExtendedProtocolsList()
24 {
25     std::vector<std::string> heapProfilerProtocolList {};
26     heapProfilerExtendedProtocols_ = std::move(heapProfilerProtocolList);
27 }
28 
Dispatch(const DispatchRequest & request)29 void HeapProfilerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request)
30 {
31     Method method = GetMethodEnum(request.GetMethod());
32     LOG_DEBUGGER(DEBUG) << "dispatch [" << request.GetMethod() << "] to HeapProfilerImpl";
33     switch (method) {
34         case Method::ADD_INSPECTED_HEAP_OBJECT:
35             AddInspectedHeapObject(request);
36             break;
37         case Method::COLLECT_GARBAGE:
38             CollectGarbage(request);
39             break;
40         case Method::ENABLE:
41             Enable(request);
42             break;
43         case Method::DISABLE:
44             Disable(request);
45             break;
46         case Method::GET_HEAP_OBJECT_ID:
47             GetHeapObjectId(request);
48             break;
49         case Method::GET_OBJECT_BY_HEAP_OBJECT_ID:
50             GetObjectByHeapObjectId(request);
51             break;
52         case Method::GET_SAMPLING_PROFILE:
53             GetSamplingProfile(request);
54             break;
55         case Method::START_SAMPLING:
56             StartSampling(request);
57             break;
58         case Method::START_TRACKING_HEAP_OBJECTS:
59             StartTrackingHeapObjects(request);
60             break;
61         case Method::STOP_SAMPLING:
62             StopSampling(request);
63             break;
64         case Method::STOP_TRACKING_HEAP_OBJECTS:
65             StopTrackingHeapObjects(request);
66             break;
67         case Method::TAKE_HEAP_SNAPSHOT:
68             TakeHeapSnapshot(request);
69             break;
70         default:
71             SendResponse(request, DispatchResponse::Fail("Unknown method: " + request.GetMethod()));
72             break;
73     }
74 }
75 
GetMethodEnum(const std::string & method)76 HeapProfilerImpl::DispatcherImpl::Method HeapProfilerImpl::DispatcherImpl::GetMethodEnum(const std::string& method)
77 {
78     if (method == "addInspectedHeapObject") {
79         return Method::ADD_INSPECTED_HEAP_OBJECT;
80     } else if (method == "collectGarbage") {
81         return Method::COLLECT_GARBAGE;
82     } else if (method == "enable") {
83         return Method::ENABLE;
84     } else if (method == "disable") {
85         return Method::DISABLE;
86     } else if (method == "getHeapObjectId") {
87         return Method::GET_HEAP_OBJECT_ID;
88     } else if (method == "getObjectByHeapObjectId") {
89         return Method::GET_OBJECT_BY_HEAP_OBJECT_ID;
90     } else if (method == "getSamplingProfile") {
91         return Method::GET_SAMPLING_PROFILE;
92     } else if (method == "startSampling") {
93         return Method::START_SAMPLING;
94     } else if (method == "startTrackingHeapObjects") {
95         return Method::START_TRACKING_HEAP_OBJECTS;
96     } else if (method == "stopSampling") {
97         return Method::STOP_SAMPLING;
98     } else if (method == "stopTrackingHeapObjects") {
99         return Method::STOP_TRACKING_HEAP_OBJECTS;
100     } else if (method == "takeHeapSnapshot") {
101         return Method::TAKE_HEAP_SNAPSHOT;
102     } else {
103         return Method::UNKNOWN;
104     }
105 }
106 
AddInspectedHeapObject(const DispatchRequest & request)107 void HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject(const DispatchRequest &request)
108 {
109     std::unique_ptr<AddInspectedHeapObjectParams> params = AddInspectedHeapObjectParams::Create(request.GetParams());
110     if (params == nullptr) {
111         SendResponse(request, DispatchResponse::Fail("wrong params"));
112         return;
113     }
114     DispatchResponse response = heapprofiler_->AddInspectedHeapObject(*params);
115     SendResponse(request, response);
116 }
117 
CollectGarbage(const DispatchRequest & request)118 void HeapProfilerImpl::DispatcherImpl::CollectGarbage(const DispatchRequest &request)
119 {
120     DispatchResponse response = heapprofiler_->CollectGarbage();
121     SendResponse(request, response);
122 }
123 
Enable(const DispatchRequest & request)124 void HeapProfilerImpl::DispatcherImpl::Enable(const DispatchRequest &request)
125 {
126     DispatchResponse response = heapprofiler_->Enable();
127     heapprofiler_->InitializeExtendedProtocolsList();
128     EnableReturns result(heapprofiler_->heapProfilerExtendedProtocols_);
129     SendResponse(request, response, result);
130 }
131 
Disable(const DispatchRequest & request)132 void HeapProfilerImpl::DispatcherImpl::Disable(const DispatchRequest &request)
133 {
134     DispatchResponse response = heapprofiler_->Disable();
135     SendResponse(request, response);
136 }
137 
GetHeapObjectId(const DispatchRequest & request)138 void HeapProfilerImpl::DispatcherImpl::GetHeapObjectId(const DispatchRequest &request)
139 {
140     std::unique_ptr<GetHeapObjectIdParams> params = GetHeapObjectIdParams::Create(request.GetParams());
141     if (params == nullptr) {
142         SendResponse(request, DispatchResponse::Fail("wrong params"));
143         return;
144     }
145 
146     HeapSnapshotObjectId objectId;
147     DispatchResponse response = heapprofiler_->GetHeapObjectId(*params, &objectId);
148     GetHeapObjectIdReturns result(std::move(objectId));
149     SendResponse(request, response, result);
150 }
151 
GetObjectByHeapObjectId(const DispatchRequest & request)152 void HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId(const DispatchRequest &request)
153 {
154     std::unique_ptr<GetObjectByHeapObjectIdParams> params = GetObjectByHeapObjectIdParams::Create(request.GetParams());
155     if (params == nullptr) {
156         SendResponse(request, DispatchResponse::Fail("wrong params"));
157         return;
158     }
159 
160     std::unique_ptr<RemoteObject> remoteObjectResult;
161     DispatchResponse response = heapprofiler_->GetObjectByHeapObjectId(*params, &remoteObjectResult);
162     if (remoteObjectResult == nullptr) {
163         SendResponse(request, response);
164         return;
165     }
166 
167     GetObjectByHeapObjectIdReturns result(std::move(remoteObjectResult));
168     SendResponse(request, response, result);
169 }
170 
GetSamplingProfile(const DispatchRequest & request)171 void HeapProfilerImpl::DispatcherImpl::GetSamplingProfile(const DispatchRequest &request)
172 {
173     std::unique_ptr<SamplingHeapProfile> profile;
174     DispatchResponse response = heapprofiler_->GetSamplingProfile(&profile);
175     if (profile == nullptr) {
176         SendResponse(request, response);
177         return;
178     }
179 
180     // The return value type of GetSamplingProfile is the same as of StopSampling.
181     StopSamplingReturns result(std::move(profile));
182     SendResponse(request, response, result);
183 }
184 
StartSampling(const DispatchRequest & request)185 void HeapProfilerImpl::DispatcherImpl::StartSampling(const DispatchRequest &request)
186 {
187     std::unique_ptr<StartSamplingParams> params = StartSamplingParams::Create(request.GetParams());
188     if (params == nullptr) {
189         SendResponse(request, DispatchResponse::Fail("wrong params"));
190         return;
191     }
192     DispatchResponse response = heapprofiler_->StartSampling(*params);
193     SendResponse(request, response);
194 }
195 
StopSampling(const DispatchRequest & request)196 void HeapProfilerImpl::DispatcherImpl::StopSampling(const DispatchRequest &request)
197 {
198     std::unique_ptr<SamplingHeapProfile> profile;
199     DispatchResponse response = heapprofiler_->StopSampling(&profile);
200     if (profile == nullptr) {
201         SendResponse(request, response);
202         return;
203     }
204 
205     StopSamplingReturns result(std::move(profile));
206     SendResponse(request, response, result);
207 }
208 
StartTrackingHeapObjects(const DispatchRequest & request)209 void HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects(const DispatchRequest &request)
210 {
211     std::unique_ptr<StartTrackingHeapObjectsParams> params =
212         StartTrackingHeapObjectsParams::Create(request.GetParams());
213     if (params == nullptr) {
214         SendResponse(request, DispatchResponse::Fail("wrong params"));
215         return;
216     }
217     DispatchResponse response = heapprofiler_->StartTrackingHeapObjects(*params);
218     SendResponse(request, response);
219 }
220 
StopTrackingHeapObjects(const DispatchRequest & request)221 void HeapProfilerImpl::DispatcherImpl::StopTrackingHeapObjects(const DispatchRequest &request)
222 {
223     std::unique_ptr<StopTrackingHeapObjectsParams> params = StopTrackingHeapObjectsParams::Create(request.GetParams());
224     if (params == nullptr) {
225         SendResponse(request, DispatchResponse::Fail("wrong params"));
226         return;
227     }
228     DispatchResponse response = heapprofiler_->StopTrackingHeapObjects(*params);
229     SendResponse(request, response);
230 }
231 
TakeHeapSnapshot(const DispatchRequest & request)232 void HeapProfilerImpl::DispatcherImpl::TakeHeapSnapshot(const DispatchRequest &request)
233 {
234     std::unique_ptr<StopTrackingHeapObjectsParams> params = StopTrackingHeapObjectsParams::Create(request.GetParams());
235     if (params == nullptr) {
236         SendResponse(request, DispatchResponse::Fail("wrong params"));
237         return;
238     }
239     DispatchResponse response = heapprofiler_->TakeHeapSnapshot(*params);
240     SendResponse(request, response);
241 }
242 
AllowNotify() const243 bool HeapProfilerImpl::Frontend::AllowNotify() const
244 {
245     return channel_ != nullptr;
246 }
247 
AddHeapSnapshotChunk(char * data,int32_t size)248 void HeapProfilerImpl::Frontend::AddHeapSnapshotChunk(char *data, int32_t size)
249 {
250     if (!AllowNotify()) {
251         return;
252     }
253 
254     tooling::AddHeapSnapshotChunk addHeapSnapshotChunk;
255     addHeapSnapshotChunk.GetChunk().resize(size);
256     for (int32_t i = 0; i < size; ++i) {
257         addHeapSnapshotChunk.GetChunk()[i] = data[i];
258     }
259 
260     channel_->SendNotification(addHeapSnapshotChunk);
261 }
262 
ReportHeapSnapshotProgress(int32_t done,int32_t total)263 void HeapProfilerImpl::Frontend::ReportHeapSnapshotProgress(int32_t done, int32_t total)
264 {
265     if (!AllowNotify()) {
266         return;
267     }
268 
269     tooling::ReportHeapSnapshotProgress reportHeapSnapshotProgress;
270     reportHeapSnapshotProgress.SetDone(done).SetTotal(total);
271     if (done >= total) {
272         reportHeapSnapshotProgress.SetFinished(true);
273     }
274     channel_->SendNotification(reportHeapSnapshotProgress);
275 }
276 
HeapStatsUpdate(HeapStat * updateData,int32_t count)277 void HeapProfilerImpl::Frontend::HeapStatsUpdate(HeapStat* updateData, int32_t count)
278 {
279     if (!AllowNotify()) {
280         return;
281     }
282     std::vector<int32_t> statsDiff;
283     for (int32_t i = 0; i < count; ++i) {
284         statsDiff.emplace_back(updateData[i].index_);
285         statsDiff.emplace_back(updateData[i].count_);
286         statsDiff.emplace_back(updateData[i].size_);
287     }
288     tooling::HeapStatsUpdate heapStatsUpdate;
289     heapStatsUpdate.SetStatsUpdate(std::move(statsDiff));
290     channel_->SendNotification(heapStatsUpdate);
291 }
292 
LastSeenObjectId(int32_t lastSeenObjectId,int64_t timeStampUs)293 void HeapProfilerImpl::Frontend::LastSeenObjectId(int32_t lastSeenObjectId, int64_t timeStampUs)
294 {
295     if (!AllowNotify()) {
296         return;
297     }
298 
299     tooling::LastSeenObjectId lastSeenObjectIdEvent;
300     lastSeenObjectIdEvent.SetLastSeenObjectId(lastSeenObjectId);
301     const int THOUSAND = 1000;
302     double timestampMS = static_cast<double>(timeStampUs) / THOUSAND;
303     lastSeenObjectIdEvent.SetTimestamp(timestampMS);
304     channel_->SendNotification(lastSeenObjectIdEvent);
305 }
306 
ResetProfiles()307 void HeapProfilerImpl::Frontend::ResetProfiles()
308 {
309     if (!AllowNotify()) {
310         return;
311     }
312 }
313 
~HeapProfilerImpl()314 HeapProfilerImpl::~HeapProfilerImpl()
315 {
316     uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm_->GetLoop());
317     if (handle_!= nullptr && loop != nullptr) {
318         uv_close(reinterpret_cast<uv_handle_t*>(handle_), [](uv_handle_t* handle) {
319             delete reinterpret_cast<uv_timer_t*>(handle);
320             handle = nullptr;
321         });
322     }
323 }
324 
AddInspectedHeapObject(const AddInspectedHeapObjectParams & params)325 DispatchResponse HeapProfilerImpl::AddInspectedHeapObject([[maybe_unused]] const AddInspectedHeapObjectParams &params)
326 {
327     return DispatchResponse::Fail("AddInspectedHeapObject not support now");
328 }
329 
CollectGarbage()330 DispatchResponse HeapProfilerImpl::CollectGarbage()
331 {
332     panda::JSNApi::TriggerGC(vm_, panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
333     panda::JSNApi::TriggerGC(vm_, panda::JSNApi::TRIGGER_GC_TYPE::SHARED_FULL_GC);
334     return DispatchResponse::Ok();
335 }
336 
Enable()337 DispatchResponse HeapProfilerImpl::Enable()
338 {
339     return DispatchResponse::Ok();
340 }
341 
Disable()342 DispatchResponse HeapProfilerImpl::Disable()
343 {
344     panda::DFXJSNApi::DestroyHeapProfiler(vm_);
345     return DispatchResponse::Ok();
346 }
347 
GetHeapObjectId(const GetHeapObjectIdParams & params,HeapSnapshotObjectId * objectId)348 DispatchResponse HeapProfilerImpl::GetHeapObjectId([[maybe_unused]] const GetHeapObjectIdParams &params,
349     HeapSnapshotObjectId *objectId)
350 {
351     ASSERT(objectId != nullptr);
352     *objectId = 0;
353     return DispatchResponse::Fail("GetHeapObjectId not support now");
354 }
355 
GetObjectByHeapObjectId(const GetObjectByHeapObjectIdParams & params,std::unique_ptr<RemoteObject> * remoteObjectResult)356 DispatchResponse HeapProfilerImpl::GetObjectByHeapObjectId([[maybe_unused]] const GetObjectByHeapObjectIdParams &params,
357     [[maybe_unused]] std::unique_ptr<RemoteObject> *remoteObjectResult)
358 {
359     return DispatchResponse::Fail("GetObjectByHeapObjectId not support now");
360 }
361 
GetSamplingProfile(std::unique_ptr<SamplingHeapProfile> * profile)362 DispatchResponse HeapProfilerImpl::GetSamplingProfile([[maybe_unused]] std::unique_ptr<SamplingHeapProfile> *profile)
363 {
364     auto samplingInfo = panda::DFXJSNApi::GetAllocationProfile(vm_);
365     if (samplingInfo == nullptr) {
366         return DispatchResponse::Fail("GetSamplingProfile fail");
367     }
368     *profile = SamplingHeapProfile::FromSamplingInfo(std::move(samplingInfo));
369     return DispatchResponse::Ok();
370 }
371 
StartSampling(const StartSamplingParams & params)372 DispatchResponse HeapProfilerImpl::StartSampling([[maybe_unused]] const StartSamplingParams &params)
373 {
374     panda::JSNApi::SetProfilerState(vm_, true);
375     uint64_t samplingInterval = static_cast<uint64_t>(params.GetSamplingInterval());
376     bool result = panda::DFXJSNApi::StartSampling(vm_, samplingInterval);
377     if (result) {
378         return DispatchResponse::Ok();
379     }
380     return DispatchResponse::Fail("StartSampling fail");
381 }
382 
StopSampling(std::unique_ptr<SamplingHeapProfile> * profile)383 DispatchResponse HeapProfilerImpl::StopSampling([[maybe_unused]] std::unique_ptr<SamplingHeapProfile> *profile)
384 {
385     DispatchResponse samplingProfile = GetSamplingProfile(profile);
386     if (samplingProfile.IsOk()) {
387         panda::DFXJSNApi::StopSampling(vm_);
388         panda::JSNApi::SetProfilerState(vm_, false);
389         return DispatchResponse::Ok();
390     }
391     return DispatchResponse::Fail("StopSampling fail");
392 }
393 
StartTrackingHeapObjects(const StartTrackingHeapObjectsParams & params)394 DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects(const StartTrackingHeapObjectsParams &params)
395 {
396     panda::JSNApi::SetProfilerState(vm_, true);
397     if (handle_ != nullptr && uv_is_active(reinterpret_cast<uv_handle_t*>(handle_))) {
398         return DispatchResponse::Ok();
399     }
400     bool traceAllocation = params.GetTrackAllocations();
401     bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_, traceAllocation, false);
402 
403     uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm_->GetLoop());
404     if (loop == nullptr) {
405         return DispatchResponse::Fail("Loop is nullptr");
406     }
407     if (handle_ == nullptr) {
408         handle_ = new uv_timer_t;
409     }
410     uv_timer_init(loop, handle_);
411     handle_->data = this;
412     uv_timer_start(handle_, HeapTrackingCallback, 0, INTERVAL * MILLI_TO_MICRO);
413     if (DebuggerApi::IsMainThread()) {
414         uv_async_send(&loop->wq_async);
415     } else {
416         uv_work_t *work = new uv_work_t;
417         uv_queue_work(loop, work, [](uv_work_t *) { }, [](uv_work_t *work, int32_t) { delete work; });
418     }
419 
420     if (result) {
421         return DispatchResponse::Ok();
422     } else {
423         return DispatchResponse::Fail("StartHeapTracking fail");
424     }
425 }
426 
HeapTrackingCallback(uv_timer_t * handle)427 void HeapProfilerImpl::HeapTrackingCallback(uv_timer_t* handle)
428 {
429     HeapProfilerImpl *heapProfilerImpl = static_cast<HeapProfilerImpl *>(handle->data);
430     if (heapProfilerImpl == nullptr) {
431         return;
432     }
433     panda::DFXJSNApi::UpdateHeapTracking(heapProfilerImpl->vm_, &(heapProfilerImpl->stream_));
434 }
435 
StopTrackingHeapObjects(const StopTrackingHeapObjectsParams & params)436 DispatchResponse HeapProfilerImpl::StopTrackingHeapObjects(const StopTrackingHeapObjectsParams &params)
437 {
438     if (handle_ != nullptr) {
439         uv_timer_stop(handle_);
440     }
441     bool result = false;
442     if (params.GetReportProgress()) {
443         HeapProfilerProgress progress(&frontend_);
444         result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, &progress, false);
445     } else {
446         result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, nullptr, false);
447     }
448     if (result) {
449         panda::JSNApi::SetProfilerState(vm_, false);
450         return DispatchResponse::Ok();
451     } else {
452         return DispatchResponse::Fail("StopHeapTracking fail");
453     }
454 }
455 
TakeHeapSnapshot(const StopTrackingHeapObjectsParams & params)456 DispatchResponse HeapProfilerImpl::TakeHeapSnapshot(const StopTrackingHeapObjectsParams &params)
457 {
458     bool captureNumericValue = params.GetCaptureNumericValue();
459     DumpSnapShotOption dumpOption;
460     dumpOption.dumpFormat = DumpFormat::JSON;
461     dumpOption.isVmMode = true;
462     dumpOption.isPrivate = false;
463     dumpOption.captureNumericValue = captureNumericValue;
464     if (params.GetReportProgress()) {
465         HeapProfilerProgress progress(&frontend_);
466         panda::DFXJSNApi::DumpHeapSnapshot(vm_, &stream_, dumpOption, &progress);
467     } else {
468         panda::DFXJSNApi::DumpHeapSnapshot(vm_, &stream_, dumpOption);
469     }
470     return DispatchResponse::Ok();
471 }
472 }  // namespace panda::ecmascript::tooling
473