• 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;
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 
~HeapProfilerImpl()253 HeapProfilerImpl::~HeapProfilerImpl()
254 {
255     uv_timer_stop(&handle_);
256 }
257 
AddInspectedHeapObject(const AddInspectedHeapObjectParams & params)258 DispatchResponse HeapProfilerImpl::AddInspectedHeapObject([[maybe_unused]] const AddInspectedHeapObjectParams &params)
259 {
260     return DispatchResponse::Fail("AddInspectedHeapObject not support now");
261 }
262 
CollectGarbage()263 DispatchResponse HeapProfilerImpl::CollectGarbage()
264 {
265     panda::JSNApi::TriggerGC(vm_, panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
266     panda::JSNApi::TriggerGC(vm_, panda::JSNApi::TRIGGER_GC_TYPE::OLD_GC);
267     return DispatchResponse::Ok();
268 }
269 
Enable()270 DispatchResponse HeapProfilerImpl::Enable()
271 {
272     return DispatchResponse::Ok();
273 }
274 
Disable()275 DispatchResponse HeapProfilerImpl::Disable()
276 {
277     panda::DFXJSNApi::DestroyHeapProfiler(vm_);
278     return DispatchResponse::Ok();
279 }
280 
GetHeapObjectId(const GetHeapObjectIdParams & params,HeapSnapshotObjectId * objectId)281 DispatchResponse HeapProfilerImpl::GetHeapObjectId([[maybe_unused]] const GetHeapObjectIdParams &params,
282     HeapSnapshotObjectId *objectId)
283 {
284     ASSERT(objectId != nullptr);
285     *objectId = 0;
286     return DispatchResponse::Fail("GetHeapObjectId not support now");
287 }
288 
GetObjectByHeapObjectId(const GetObjectByHeapObjectIdParams & params,std::unique_ptr<RemoteObject> * remoteObjectResult)289 DispatchResponse HeapProfilerImpl::GetObjectByHeapObjectId([[maybe_unused]] const GetObjectByHeapObjectIdParams &params,
290     [[maybe_unused]] std::unique_ptr<RemoteObject> *remoteObjectResult)
291 {
292     return DispatchResponse::Fail("GetObjectByHeapObjectId not support now");
293 }
294 
GetSamplingProfile(std::unique_ptr<SamplingHeapProfile> * profile)295 DispatchResponse HeapProfilerImpl::GetSamplingProfile([[maybe_unused]] std::unique_ptr<SamplingHeapProfile> *profile)
296 {
297     auto samplingInfo = panda::DFXJSNApi::GetAllocationProfile(vm_);
298     if (samplingInfo == nullptr) {
299         return DispatchResponse::Fail("GetSamplingProfile fail");
300     }
301     *profile = SamplingHeapProfile::FromSamplingInfo(std::move(samplingInfo));
302     return DispatchResponse::Ok();
303 }
304 
StartSampling(const StartSamplingParams & params)305 DispatchResponse HeapProfilerImpl::StartSampling([[maybe_unused]] const StartSamplingParams &params)
306 {
307     panda::JSNApi::SetProfilerState(vm_, true);
308     uint64_t samplingInterval = static_cast<uint64_t>(params.GetSamplingInterval());
309     bool result = panda::DFXJSNApi::StartSampling(vm_, samplingInterval);
310     if (result) {
311         return DispatchResponse::Ok();
312     }
313     return DispatchResponse::Fail("StartSampling fail");
314 }
315 
StopSampling(std::unique_ptr<SamplingHeapProfile> * profile)316 DispatchResponse HeapProfilerImpl::StopSampling([[maybe_unused]] std::unique_ptr<SamplingHeapProfile> *profile)
317 {
318     DispatchResponse samplingProfile = GetSamplingProfile(profile);
319     if (samplingProfile.IsOk()) {
320         panda::DFXJSNApi::StopSampling(vm_);
321         panda::JSNApi::SetProfilerState(vm_, false);
322         return DispatchResponse::Ok();
323     }
324     return DispatchResponse::Fail("StopSampling fail");
325 }
326 
StartTrackingHeapObjects(const StartTrackingHeapObjectsParams & params)327 DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects(const StartTrackingHeapObjectsParams &params)
328 {
329     panda::JSNApi::SetProfilerState(vm_, true);
330     if (uv_is_active(reinterpret_cast<uv_handle_t*>(&handle_))) {
331         return DispatchResponse::Ok();
332     }
333     bool traceAllocation = params.GetTrackAllocations();
334     bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_, traceAllocation, false);
335 
336     uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm_->GetLoop());
337     if (loop == nullptr) {
338         return DispatchResponse::Fail("Loop is nullptr");
339     }
340     uv_timer_init(loop, &handle_);
341     handle_.data = this;
342     uv_timer_start(&handle_, HeapTrackingCallback, 0, INTERVAL * MILLI_TO_MICRO);
343 
344     uv_work_t *work = new uv_work_t;
345     uv_queue_work(loop, work, [](uv_work_t *) { }, [](uv_work_t *work, int32_t) { delete work; });
346 
347     if (result) {
348         return DispatchResponse::Ok();
349     } else {
350         return DispatchResponse::Fail("StartHeapTracking fail");
351     }
352 }
353 
HeapTrackingCallback(uv_timer_t * handle)354 void HeapProfilerImpl::HeapTrackingCallback(uv_timer_t* handle)
355 {
356     HeapProfilerImpl *heapProfilerImpl = static_cast<HeapProfilerImpl *>(handle->data);
357     if (heapProfilerImpl == nullptr) {
358         return;
359     }
360     panda::DFXJSNApi::UpdateHeapTracking(heapProfilerImpl->vm_, &(heapProfilerImpl->stream_));
361 }
362 
StopTrackingHeapObjects(const StopTrackingHeapObjectsParams & params)363 DispatchResponse HeapProfilerImpl::StopTrackingHeapObjects(const StopTrackingHeapObjectsParams &params)
364 {
365     uv_timer_stop(&handle_);
366     bool result = false;
367     if (params.GetReportProgress()) {
368         HeapProfilerProgress progress(&frontend_);
369         result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, &progress, false);
370     } else {
371         result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, nullptr, false);
372     }
373     if (result) {
374         panda::JSNApi::SetProfilerState(vm_, false);
375         return DispatchResponse::Ok();
376     } else {
377         return DispatchResponse::Fail("StopHeapTracking fail");
378     }
379 }
380 
TakeHeapSnapshot(const StopTrackingHeapObjectsParams & params)381 DispatchResponse HeapProfilerImpl::TakeHeapSnapshot(const StopTrackingHeapObjectsParams &params)
382 {
383     bool captureNumericValue = params.GetCaptureNumericValue();
384     if (params.GetReportProgress()) {
385         HeapProfilerProgress progress(&frontend_);
386         panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, &progress, true, false, captureNumericValue);
387     } else {
388         panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, nullptr, true, false, captureNumericValue);
389     }
390     return DispatchResponse::Ok();
391 }
392 }  // namespace panda::ecmascript::tooling
393