1 /*
2 * Copyright (c) 2021-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 "ecmascript/napi/include/dfx_jsnapi.h"
17
18 #include "ecmascript/builtins/builtins_ark_tools.h"
19 #include "ecmascript/dfx/hprof/heap_profiler.h"
20 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
21 #include "ecmascript/dfx/tracing/tracing.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/mem/c_string.h"
24 #include "ecmascript/mem/heap-inl.h"
25 #include "ecmascript/mem/gc_stats.h"
26 #include "ecmascript/napi/include/jsnapi.h"
27 #include "ecmascript/dfx/hprof/file_stream.h"
28 #include "ecmascript/dfx/vm_thread_control.h"
29
30 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
31 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
32 #include "ecmascript/dfx/cpu_profiler/samples_record.h"
33 #endif
34 #if defined(ENABLE_DUMP_IN_FAULTLOG)
35 #include "faultloggerd_client.h"
36 #include "uv.h"
37 #endif
38
39 namespace panda {
40 using ecmascript::CString;
41 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
42 using BuiltinsArkTools = ecmascript::builtins::BuiltinsArkTools;
43 using ecmascript::CpuProfiler;
44 #endif
45 using ecmascript::EcmaString;
46 using ecmascript::JSTaggedValue;
47 using ecmascript::GCStats;
48 template<typename T>
49 using JSHandle = ecmascript::JSHandle<T>;
50 using ecmascript::FileStream;
51 using ecmascript::FileDescriptorStream;
52 using ecmascript::CMap;
53 using ecmascript::Tracing;
54
DumpHeapSnapshot(const EcmaVM * vm,int dumpFormat,const std::string & path,bool isVmMode,bool isPrivate,bool captureNumericValue)55 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat,
56 [[maybe_unused]] const std::string &path, [[maybe_unused]] bool isVmMode,
57 [[maybe_unused]] bool isPrivate, [[maybe_unused]] bool captureNumericValue)
58 {
59 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
60 FileStream stream(path);
61 DumpHeapSnapshot(vm, dumpFormat, &stream, nullptr, isVmMode, isPrivate, captureNumericValue);
62 #else
63 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
64 #endif
65 }
66
DumpHeapSnapshot(const EcmaVM * vm,int dumpFormat,Stream * stream,Progress * progress,bool isVmMode,bool isPrivate,bool captureNumericValue,bool isFullGC)67 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat,
68 [[maybe_unused]] Stream *stream, [[maybe_unused]] Progress *progress,
69 [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate,
70 [[maybe_unused]] bool captureNumericValue, [[maybe_unused]] bool isFullGC)
71 {
72 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
73 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
74 const_cast<EcmaVM *>(vm));
75 heapProfile->DumpHeapSnapshot(ecmascript::DumpFormat(dumpFormat), stream, progress,
76 isVmMode, isPrivate, captureNumericValue, isFullGC);
77 #else
78 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
79 #endif
80 }
81
82 [[maybe_unused]] static uint8_t killCount = 0;
83
DumpCpuProfile(const EcmaVM * vm,int dumpFormat,bool isVmMode,bool isPrivate,bool captureNumericValue,bool isFullGC)84 void DFXJSNApi::DumpCpuProfile([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat,
85 [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate,
86 [[maybe_unused]] bool captureNumericValue, [[maybe_unused]] bool isFullGC)
87 {
88 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
89 #if defined(ENABLE_DUMP_IN_FAULTLOG)
90 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
91 // for CpuProfiler kill contral
92 if (DFXJSNApi::StopCpuProfilerForColdStart(vm)) {
93 return;
94 }
95
96 (void)killCount;
97 if (DFXJSNApi::CpuProfilerSamplingAnyTime(vm)) {
98 killCount++;
99 return;
100 }
101 #endif // ECMASCRIPT_SUPPORT_CPUPROFILER
102 #endif // ENABLE_DUMP_IN_FAULTLOG
103 #endif // ECMASCRIPT_SUPPORT_SNAPSHOT
104 }
105
DumpHeapSnapshot(const EcmaVM * vm,int dumpFormat,bool isVmMode,bool isPrivate,bool captureNumericValue,bool isFullGC)106 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat,
107 [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate,
108 [[maybe_unused]] bool captureNumericValue, [[maybe_unused]] bool isFullGC)
109 {
110 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
111 #if defined(ENABLE_DUMP_IN_FAULTLOG)
112 auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
113 options.SwitchStartGlobalLeakCheck();
114 if (options.EnableGlobalLeakCheck() && options.IsStartGlobalLeakCheck()) {
115 int32_t stackTraceFd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_STACKTRACE));
116 if (stackTraceFd < 0) {
117 options.SwitchStartGlobalLeakCheck();
118 } else {
119 vm->GetJSThread()->SetStackTraceFd(stackTraceFd);
120 }
121 }
122 // Write in faultlog for heap leak.
123 int32_t fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_HEAP_SNAPSHOT));
124 if (fd < 0) {
125 LOG_ECMA(ERROR) << "Write FD failed, fd" << fd;
126 return;
127 }
128 FileDescriptorStream stream(fd);
129 DumpHeapSnapshot(vm, dumpFormat, &stream, nullptr, isVmMode, isPrivate, captureNumericValue, isFullGC);
130 #endif // ENABLE_DUMP_IN_FAULTLOG
131 #else
132 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
133 #endif // ECMASCRIPT_SUPPORT_SNAPSHOT
134 }
135
DumpHeapSnapshotAllVMs(const EcmaVM * vm,int dumpFormat,bool isVmMode,bool isPrivate,bool captureNumericValue,bool isFullGC)136 void DFXJSNApi::DumpHeapSnapshotAllVMs([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat,
137 [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate,
138 [[maybe_unused]] bool captureNumericValue, [[maybe_unused]] bool isFullGC)
139 {
140 #if defined(ENABLE_DUMP_IN_FAULTLOG)
141 if (vm->IsWorkerThread()) {
142 LOG_ECMA(ERROR) << "this is a workthread!";
143 return;
144 }
145 // dump host vm.
146 DumpHeapSnapshot(vm, dumpFormat, isVmMode, isPrivate, captureNumericValue, isFullGC);
147 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
148 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(workerVm->GetLoop());
149 if (loop == nullptr) {
150 LOG_ECMA(ERROR) << "loop is nullptr";
151 return;
152 }
153 struct DumpForSnapShotStruct *dumpStruct = new DumpForSnapShotStruct();
154 dumpStruct->vm = workerVm;
155 dumpStruct->dumpFormat = dumpFormat;
156 dumpStruct->isVmMode = isVmMode;
157 dumpStruct->isPrivate = isPrivate;
158 dumpStruct->captureNumericValue = captureNumericValue;
159 dumpStruct->isFullGC = isFullGC;
160 uv_work_t *work = new uv_work_t;
161 work->data = (void *)dumpStruct;
162 if (uv_loop_alive(loop) == 0) {
163 LOG_ECMA(ERROR) << "uv_loop_alive is dead";
164 return;
165 }
166 uv_queue_work(
167 loop,
168 work,
169 [](uv_work_t *) {},
170 [](uv_work_t *work, int32_t) {
171 struct DumpForSnapShotStruct *dump = (struct DumpForSnapShotStruct *)(work->data);
172 DumpHeapSnapshot(dump->vm, dump->dumpFormat, dump->isVmMode,
173 dump->isPrivate, dump->captureNumericValue, dump->isFullGC);
174 delete dump;
175 delete work;
176 });
177 });
178 #endif
179 }
180
DestroyHeapProfiler(const EcmaVM * vm)181 void DFXJSNApi::DestroyHeapProfiler([[maybe_unused]] const EcmaVM *vm)
182 {
183 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
184 ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm));
185 #else
186 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot";
187 #endif
188 }
189
BuildNativeAndJsStackTrace(const EcmaVM * vm,std::string & stackTraceStr)190 bool DFXJSNApi::BuildNativeAndJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
191 {
192 LOG_ECMA(INFO) <<"BuildJsStackInfoList start";
193 std::vector<JsFrameInfo> jf = ecmascript::JsStackInfo::BuildJsStackInfo(vm->GetAssociatedJSThread());
194 LOG_ECMA(INFO) <<"BuildJsStackInfoList JsFrameInfo";
195 for (uint32_t i = 0; i < jf.size(); ++i) {
196 std::string functionname = jf[i].functionName;
197 std::string filename = jf[i].fileName;
198 std::string pos = jf[i].pos;
199 uintptr_t *nativepointer = jf[i].nativePointer;
200 LOG_ECMA(INFO) << "BuildJsStackInfoList functionname: " << functionname;
201 LOG_ECMA(INFO) << "BuildJsStackInfoList filenaem: " << filename;
202 LOG_ECMA(INFO) << "BuildJsStackInfoList pos: " << pos;
203 LOG_ECMA(INFO) << "BuildJsStackInfoList nativepointer: " << nativepointer;
204 }
205 stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), true);
206 if (stackTraceStr.empty()) {
207 return false;
208 }
209 return true;
210 }
211
BuildJsStackTrace(const EcmaVM * vm,std::string & stackTraceStr)212 bool DFXJSNApi::BuildJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
213 {
214 stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), false);
215 if (stackTraceStr.empty()) {
216 return false;
217 }
218 return true;
219 }
220
StartHeapTracking(const EcmaVM * vm,double timeInterval,bool isVmMode,Stream * stream,bool traceAllocation,bool newThread)221 bool DFXJSNApi::StartHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] double timeInterval,
222 [[maybe_unused]] bool isVmMode, [[maybe_unused]] Stream *stream,
223 [[maybe_unused]] bool traceAllocation, [[maybe_unused]] bool newThread)
224 {
225 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
226 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
227 const_cast<EcmaVM *>(vm));
228 return heapProfile->StartHeapTracking(timeInterval, isVmMode, stream, traceAllocation, newThread);
229 #else
230 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
231 return false;
232 #endif
233 }
234
UpdateHeapTracking(const EcmaVM * vm,Stream * stream)235 bool DFXJSNApi::UpdateHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream *stream)
236 {
237 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
238 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
239 const_cast<EcmaVM *>(vm));
240 return heapProfile->UpdateHeapTracking(stream);
241 #else
242 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
243 return false;
244 #endif
245 }
246
StopHeapTracking(const EcmaVM * vm,const std::string & filePath,bool newThread)247 bool DFXJSNApi::StopHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const std::string &filePath,
248 [[maybe_unused]] bool newThread)
249 {
250 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
251 FileStream stream(filePath);
252 return StopHeapTracking(vm, &stream, nullptr, newThread);
253 #else
254 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
255 return false;
256 #endif
257 }
258
StopHeapTracking(const EcmaVM * vm,Stream * stream,Progress * progress,bool newThread)259 bool DFXJSNApi::StopHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream* stream,
260 [[maybe_unused]] Progress *progress, [[maybe_unused]] bool newThread)
261 {
262 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
263 bool result = false;
264 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
265 const_cast<EcmaVM *>(vm));
266 result = heapProfile->StopHeapTracking(stream, progress, newThread);
267 ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm));
268 return result;
269 #else
270 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking";
271 return false;
272 #endif
273 }
274
PrintStatisticResult(const EcmaVM * vm)275 void DFXJSNApi::PrintStatisticResult(const EcmaVM *vm)
276 {
277 ecmascript::GCStats gcstats(vm->GetHeap());
278 gcstats.PrintStatisticResult();
279 }
280
StartRuntimeStat(EcmaVM * vm)281 void DFXJSNApi::StartRuntimeStat(EcmaVM *vm)
282 {
283 vm->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(true);
284 }
285
StopRuntimeStat(EcmaVM * vm)286 void DFXJSNApi::StopRuntimeStat(EcmaVM *vm)
287 {
288 vm->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(false);
289 }
290
GetArrayBufferSize(const EcmaVM * vm)291 size_t DFXJSNApi::GetArrayBufferSize(const EcmaVM *vm)
292 {
293 return vm->GetHeap()->GetArrayBufferSize();
294 }
295
GetHeapTotalSize(const EcmaVM * vm)296 size_t DFXJSNApi::GetHeapTotalSize(const EcmaVM *vm)
297 {
298 return vm->GetHeap()->GetCommittedSize();
299 }
300
GetHeapUsedSize(const EcmaVM * vm)301 size_t DFXJSNApi::GetHeapUsedSize(const EcmaVM *vm)
302 {
303 return vm->GetHeap()->GetLiveObjectSize();
304 }
305
GetHeapObjectSize(const EcmaVM * vm)306 size_t DFXJSNApi::GetHeapObjectSize(const EcmaVM *vm)
307 {
308 return vm->GetHeap()->GetHeapObjectSize();
309 }
310
GetHeapLimitSize(const EcmaVM * vm)311 size_t DFXJSNApi::GetHeapLimitSize(const EcmaVM *vm)
312 {
313 return vm->GetHeap()->GetHeapLimitSize();
314 }
315
isOverLimit(const EcmaVM * vm)316 bool DFXJSNApi::isOverLimit(const EcmaVM *vm)
317 {
318 return vm->isOverLimit();
319 }
320
SetOverLimit(EcmaVM * vm,bool state)321 void DFXJSNApi::SetOverLimit(EcmaVM *vm, bool state)
322 {
323 vm->SetOverLimit(state);
324 }
325
GetHeapPrepare(const EcmaVM * vm)326 void DFXJSNApi::GetHeapPrepare(const EcmaVM *vm)
327 {
328 const_cast<ecmascript::Heap *>(vm->GetHeap())->Prepare();
329 }
330
NotifyApplicationState(EcmaVM * vm,bool inBackground)331 void DFXJSNApi::NotifyApplicationState(EcmaVM *vm, bool inBackground)
332 {
333 const_cast<ecmascript::Heap *>(vm->GetHeap())->ChangeGCParams(inBackground);
334 }
335
NotifyIdleStatusControl(const EcmaVM * vm,std::function<void (bool)> callback)336 void DFXJSNApi::NotifyIdleStatusControl(const EcmaVM *vm, std::function<void(bool)> callback)
337 {
338 const_cast<ecmascript::Heap *>(vm->GetHeap())->InitializeIdleStatusControl(callback);
339 }
340
NotifyIdleTime(const EcmaVM * vm,int idleMicroSec)341 void DFXJSNApi::NotifyIdleTime(const EcmaVM *vm, int idleMicroSec)
342 {
343 const_cast<ecmascript::Heap *>(vm->GetHeap())->TriggerIdleCollection(idleMicroSec);
344 }
345
NotifyMemoryPressure(EcmaVM * vm,bool inHighMemoryPressure)346 void DFXJSNApi::NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure)
347 {
348 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyMemoryPressure(inHighMemoryPressure);
349 }
350
NotifyFinishColdStart(EcmaVM * vm,bool isConvinced)351 void DFXJSNApi::NotifyFinishColdStart(EcmaVM *vm, bool isConvinced)
352 {
353 if (isConvinced) {
354 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyFinishColdStart();
355 } else {
356 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyFinishColdStartSoon();
357 }
358 }
359
NotifyHighSensitive(EcmaVM * vm,bool isStart)360 void DFXJSNApi::NotifyHighSensitive(EcmaVM *vm, bool isStart)
361 {
362 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyHighSensitive(isStart);
363 }
364
StopCpuProfilerForColdStart(const EcmaVM * vm)365 bool DFXJSNApi::StopCpuProfilerForColdStart([[maybe_unused]] const EcmaVM *vm)
366 {
367 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
368 bool success = false;
369 auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
370 if (options.EnableCpuProfilerColdStartMainThread()) {
371 success = true;
372 DFXJSNApi::StopCpuProfilerForFile(vm);
373 }
374
375 if (options.EnableCpuProfilerColdStartWorkerThread()) {
376 success = true;
377 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
378 if (workerVm->GetJSThread()->GetIsProfiling()) {
379 DFXJSNApi::StopCpuProfilerForFile(workerVm);
380 }
381 });
382 }
383
384 return success;
385 #else
386 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
387 return false;
388 #endif
389 }
390
CpuProfilerSamplingAnyTime(const EcmaVM * vm)391 bool DFXJSNApi::CpuProfilerSamplingAnyTime([[maybe_unused]] const EcmaVM *vm)
392 {
393 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
394 (void)killCount;
395 bool success = false;
396 const uint8_t KILL_COUNT_FACTOR = 2;
397 auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
398 if (options.EnableCpuProfilerAnyTimeMainThread()) {
399 success = true;
400 if (killCount % KILL_COUNT_FACTOR == 0) {
401 uint8_t fileCount = killCount / KILL_COUNT_FACTOR + 1;
402 LOG_ECMA(INFO) << "Start CpuProfiler Any Time Main Thread, killCount = " << killCount;
403 std::string fileName = ConvertToStdString(const_cast<EcmaVM *>(vm)->GetBundleName())
404 + "_" + std::to_string(fileCount) + ".cpuprofile";
405 if (!BuiltinsArkTools::CreateFile(fileName)) {
406 LOG_ECMA(ERROR) << "createFile failed " << fileName;
407 } else {
408 DFXJSNApi::StartCpuProfilerForFile(vm, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
409 }
410 } else {
411 LOG_ECMA(INFO) << "Stop CpuProfiler Any Time Main Thread, killCount = " << killCount;
412 if (vm->GetJSThread()->GetIsProfiling()) {
413 DFXJSNApi::StopCpuProfilerForFile(vm);
414 }
415 }
416 }
417
418 if (options.EnableCpuProfilerAnyTimeWorkerThread()) {
419 success = true;
420 if (killCount % KILL_COUNT_FACTOR == 0) {
421 uint8_t fileCount = killCount / KILL_COUNT_FACTOR + 1;
422 LOG_ECMA(INFO) << "Start CpuProfiler Any Time Worker Thread, killCount = " << killCount;
423 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
424 auto *thread = workerVm->GetAssociatedJSThread();
425 std::string fileName = ConvertToStdString(workerVm->GetBundleName()) + "_"
426 + std::to_string(thread->GetThreadId()) + "_"
427 + std::to_string(fileCount) + ".cpuprofile";
428 if (!BuiltinsArkTools::CreateFile(fileName)) {
429 LOG_ECMA(ERROR) << "createFile failed " << fileName;
430 } else {
431 thread->SetCpuProfileName(fileName);
432 thread->SetNeedProfiling(true);
433 }
434 });
435 } else {
436 LOG_ECMA(INFO) << "Stop CpuProfiler Any Time Worker Thread, killCount = " << killCount;
437 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void {
438 auto *thread = workerVm->GetAssociatedJSThread();
439 if (thread->GetIsProfiling()) {
440 DFXJSNApi::StopCpuProfilerForFile(workerVm);
441 }
442 thread->SetNeedProfiling(false);
443 });
444 }
445 }
446
447 return success;
448 #else
449 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
450 return false;
451 #endif
452 }
453
StartCpuProfilerForFile(const EcmaVM * vm,const std::string & fileName,int interval)454 void DFXJSNApi::StartCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm,
455 [[maybe_unused]] const std::string &fileName,
456 [[maybe_unused]] int interval)
457 {
458 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
459 if (interval < 0) {
460 LOG_ECMA(ERROR) << "Sampling interval is illegal";
461 return;
462 }
463 if (vm == nullptr) {
464 return;
465 }
466 CpuProfiler *profiler = vm->GetProfiler();
467 if (profiler == nullptr) {
468 profiler = new CpuProfiler(vm, interval);
469 const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
470 }
471 profiler->StartCpuProfilerForFile(fileName);
472 #else
473 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
474 #endif
475 }
476
StopCpuProfilerForFile(const EcmaVM * vm)477 void DFXJSNApi::StopCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm)
478 {
479 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
480 if (vm == nullptr) {
481 return;
482 }
483 CpuProfiler *profiler = vm->GetProfiler();
484 if (profiler == nullptr) {
485 return;
486 }
487 profiler->StopCpuProfilerForFile();
488 delete profiler;
489 profiler = nullptr;
490 const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
491 #else
492 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
493 #endif
494 }
495
StartCpuProfilerForInfo(const EcmaVM * vm,int interval)496 void DFXJSNApi::StartCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval)
497 {
498 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
499 if (interval < 0) {
500 LOG_ECMA(ERROR) << "Sampling interval is illegal";
501 return;
502 }
503 if (vm == nullptr) {
504 return;
505 }
506 CpuProfiler *profiler = vm->GetProfiler();
507 if (profiler == nullptr) {
508 profiler = new CpuProfiler(vm, interval);
509 const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
510 }
511 profiler->StartCpuProfilerForInfo();
512 #else
513 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
514 #endif
515 }
516
StopCpuProfilerForInfo(const EcmaVM * vm)517 std::unique_ptr<ProfileInfo> DFXJSNApi::StopCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm)
518 {
519 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
520 if (vm == nullptr) {
521 return nullptr;
522 }
523 CpuProfiler *profiler = vm->GetProfiler();
524 if (profiler == nullptr) {
525 return nullptr;
526 }
527 auto profile = profiler->StopCpuProfilerForInfo();
528 if (profile == nullptr) {
529 LOG_DEBUGGER(ERROR) << "Transfer CpuProfiler::StopCpuProfilerImpl is failure";
530 }
531 delete profiler;
532 profiler = nullptr;
533 const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
534 return profile;
535 #else
536 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
537 return nullptr;
538 #endif
539 }
540
SetCpuSamplingInterval(const EcmaVM * vm,int interval)541 void DFXJSNApi::SetCpuSamplingInterval([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval)
542 {
543 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
544 if (interval < 0) {
545 LOG_ECMA(ERROR) << "Sampling interval is illegal";
546 return;
547 }
548 LOG_ECMA(INFO) << "SetCpuProfilerSamplingInterval, Sampling interval is: " << interval;
549 if (vm == nullptr) {
550 return;
551 }
552 CpuProfiler *profiler = vm->GetProfiler();
553 if (profiler == nullptr) {
554 profiler = new CpuProfiler(vm, interval);
555 const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
556 return;
557 }
558 profiler->SetCpuSamplingInterval(interval);
559 #else
560 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
561 #endif
562 }
563
SuspendVM(const EcmaVM * vm)564 bool DFXJSNApi::SuspendVM([[maybe_unused]] const EcmaVM *vm)
565 {
566 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
567 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
568 return vmThreadControl->NotifyVMThreadSuspension();
569 #else
570 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
571 return false;
572 #endif
573 }
574
ResumeVM(const EcmaVM * vm)575 void DFXJSNApi::ResumeVM([[maybe_unused]] const EcmaVM *vm)
576 {
577 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
578 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
579 vmThreadControl->ResumeVM();
580 #else
581 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
582 #endif
583 }
584
IsSuspended(const EcmaVM * vm)585 bool DFXJSNApi::IsSuspended([[maybe_unused]] const EcmaVM *vm)
586 {
587 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
588 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
589 return vmThreadControl->IsSuspended();
590 #else
591 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
592 return false;
593 #endif
594 }
595
TerminateExecution(const EcmaVM * vm)596 void DFXJSNApi::TerminateExecution(const EcmaVM *vm)
597 {
598 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
599 vmThreadControl->RequestTerminateExecution();
600 }
601
CheckSafepoint(const EcmaVM * vm)602 bool DFXJSNApi::CheckSafepoint([[maybe_unused]] const EcmaVM *vm)
603 {
604 #if defined(ECMASCRIPT_SUPPORT_SNAPSHOT)
605 ecmascript::JSThread* thread = vm->GetJSThread();
606 return thread->CheckSafepoint();
607 #else
608 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot";
609 return false;
610 #endif
611 }
612
BuildJsStackInfoList(const EcmaVM * hostVm,uint32_t tid,std::vector<JsFrameInfo> & jsFrames)613 bool DFXJSNApi::BuildJsStackInfoList(const EcmaVM *hostVm, uint32_t tid, std::vector<JsFrameInfo>& jsFrames)
614 {
615 EcmaVM *vm;
616 if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
617 vm = const_cast<EcmaVM*>(hostVm);
618 } else {
619 vm = const_cast<EcmaVM*>(hostVm)->GetWorkerVm(tid);
620 if (vm == nullptr) {
621 return false;
622 }
623 }
624 jsFrames = ecmascript::JsStackInfo::BuildJsStackInfo(vm->GetAssociatedJSThread());
625 if (jsFrames.size() > 0) {
626 return true;
627 }
628 return false;
629 }
630
StartSampling(const EcmaVM * vm,uint64_t samplingInterval)631 bool DFXJSNApi::StartSampling([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] uint64_t samplingInterval)
632 {
633 #if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING)
634 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
635 const_cast<EcmaVM *>(vm));
636 return heapProfile->StartHeapSampling(samplingInterval);
637 #else
638 LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling";
639 return false;
640 #endif
641 }
642
GetAllocationProfile(const EcmaVM * vm)643 const SamplingInfo *DFXJSNApi::GetAllocationProfile([[maybe_unused]] const EcmaVM *vm)
644 {
645 #if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING)
646 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
647 const_cast<EcmaVM *>(vm));
648 return heapProfile->GetAllocationProfile();
649 #else
650 LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling";
651 return nullptr;
652 #endif
653 }
654
StopSampling(const EcmaVM * vm)655 void DFXJSNApi::StopSampling([[maybe_unused]] const EcmaVM *vm)
656 {
657 #if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING)
658 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
659 const_cast<EcmaVM *>(vm));
660 heapProfile->StopHeapSampling();
661 #else
662 LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling";
663 #endif
664 }
665
666 // release or debug hap : aa start -p 'dumpheap'
667 // aa start -p 'profile'
StartProfiler(EcmaVM * vm,const ProfilerOption & option,int tid,int32_t instanceId,const DebuggerPostTask & debuggerPostTask,bool isDebugApp)668 bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, int tid,
669 int32_t instanceId, const DebuggerPostTask &debuggerPostTask, bool isDebugApp)
670 {
671 LOG_ECMA(INFO) << "DFXJSNApi::StartProfiler, type = " << (int)option.profilerType
672 << ", tid = " << tid << ", isDebugApp = " << isDebugApp;
673 JSNApi::DebugOption debugOption;
674 debugOption.libraryPath = option.libraryPath;
675 if (option.profilerType == ProfilerType::CPU_PROFILER) {
676 debugOption.isDebugMode = false;
677 if (JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp)) {
678 StartCpuProfilerForInfo(vm, option.interval);
679 return true;
680 } else {
681 LOG_ECMA(ERROR) << "DFXJSNApi:Failed to StartDebugger";
682 return false;
683 }
684 } else {
685 debugOption.isDebugMode = true;
686 return JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp);
687 }
688 }
689
ResumeVMById(EcmaVM * hostVm,uint32_t tid)690 void DFXJSNApi::ResumeVMById(EcmaVM *hostVm, uint32_t tid)
691 {
692 if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
693 ResumeVM(hostVm);
694 } else {
695 hostVm->ResumeWorkerVm(tid);
696 }
697 }
698
SuspendVMById(EcmaVM * hostVm,uint32_t tid)699 bool DFXJSNApi::SuspendVMById(EcmaVM *hostVm, uint32_t tid)
700 {
701 bool success = false;
702 if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
703 success = SuspendVM(hostVm);
704 LOG_ECMA(INFO) << "The main thread, SuspendVMById succeeded: " << success;
705 return success;
706 } else {
707 success = hostVm->SuspendWorkerVm(tid);
708 LOG_ECMA(INFO) << "The worker thread, SuspendVMById succeeded: " << success;
709 return success;
710 }
711 }
712
StartTracing(const EcmaVM * vm,std::string & categories)713 bool DFXJSNApi::StartTracing([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] std::string &categories)
714 {
715 #if defined(ECMASCRIPT_SUPPORT_TRACING)
716 if (vm == nullptr) {
717 return false;
718 }
719 Tracing *tracing = vm->GetTracing();
720 if (tracing == nullptr) {
721 tracing = new Tracing(vm);
722 const_cast<EcmaVM *>(vm)->SetTracing(tracing);
723 }
724 tracing->StartTracing(categories);
725 return true;
726 #else
727 LOG_ECMA(ERROR) << "Not support arkcompiler tracing";
728 return false;
729 #endif
730 }
731
StopTracing(const EcmaVM * vm)732 std::unique_ptr<std::vector<TraceEvent>> DFXJSNApi::StopTracing([[maybe_unused]] const EcmaVM *vm)
733 {
734 #if defined(ECMASCRIPT_SUPPORT_TRACING)
735 if (vm == nullptr) {
736 return nullptr;
737 }
738 Tracing *tracing = vm->GetTracing();
739 if (tracing == nullptr) {
740 LOG_ECMA(ERROR) << "StopTracing tracing is nullptr";
741 return nullptr;
742 }
743 auto traceEvents = tracing->StopTracing();
744 if (traceEvents == nullptr) {
745 LOG_ECMA(ERROR) << "trace events is nullptr";
746 }
747 delete tracing;
748 tracing = nullptr;
749 const_cast<EcmaVM *>(vm)->SetTracing(nullptr);
750 return traceEvents;
751 #else
752 LOG_ECMA(ERROR) << "Not support arkcompiler tracing";
753 return nullptr;
754 #endif
755 }
756
GetTracingBufferUseage(const EcmaVM * vm,double & percentFull,uint32_t & eventCount,double & value)757 void DFXJSNApi::GetTracingBufferUseage([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] double &percentFull,
758 [[maybe_unused]] uint32_t &eventCount, [[maybe_unused]] double &value)
759 {
760 #if defined(ECMASCRIPT_SUPPORT_TRACING)
761 if (vm == nullptr) {
762 return;
763 }
764 ecmascript::Tracing *tracing = vm->GetTracing();
765 if (tracing == nullptr) {
766 LOG_ECMA(ERROR) << "GetTracingBufferUseage tracing is nullptr";
767 } else {
768 tracing->GetBufferUseage(percentFull, eventCount, value);
769 }
770 #else
771 LOG_ECMA(ERROR) << "Not support arkcompiler tracing";
772 #endif
773 }
774 } // namespace panda
775