• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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/dfx/hprof/heap_profiler_interface.h"
17 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
18 #include "ecmascript/dfx/vmstat/runtime_stat.h"
19 #include "ecmascript/mem/heap.h"
20 #include "ecmascript/mem/concurrent_marker.h"
21 #include "ecmascript/napi/include/dfx_jsnapi.h"
22 #include "ecmascript/tests/test_helper.h"
23 
24 using namespace panda;
25 using namespace panda::ecmascript;
26 
27 namespace panda::test {
28 class DFXJSNApiTests : public testing::Test {
29 public:
SetUpTestCase()30     static void SetUpTestCase()
31     {
32         GTEST_LOG_(INFO) << "SetUpTestCase";
33     }
34 
TearDownTestCase()35     static void TearDownTestCase()
36     {
37         GTEST_LOG_(INFO) << "TearDownCase";
38     }
39 
SetUp()40     void SetUp() override
41     {
42         TestHelper::CreateEcmaVMWithScope(vm_, thread_, scope_);
43         vm_->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(true);
44         vm_->SetEnableForceGC(false);
45     }
46 
TearDown()47     void TearDown() override
48     {
49         TestHelper::DestroyEcmaVMWithScope(vm_, scope_);
50     }
51 
52 protected:
53     EcmaVM *vm_ {nullptr};
54     JSThread *thread_ = {nullptr};
55     EcmaHandleScope *scope_ {nullptr};
56 };
57 
MatchJSONLineHeader(std::fstream & fs,const std::string filePath,int lineNum,CString lineContent)58 bool MatchJSONLineHeader(std::fstream &fs, const std::string filePath, int lineNum, CString lineContent)
59 {
60     CString tempLineContent = "";
61     int lineCount = 1;
62     fs.open(filePath.c_str(), std::ios::in);
63     while (getline(fs, tempLineContent)) {
64         if (lineNum == lineCount && tempLineContent.find(lineContent) != CString::npos) {
65             fs.close();
66             fs.clear();
67             return true;
68         }
69         lineCount++;
70     }
71     fs.close();
72     fs.clear();
73     return false;
74 }
75 
HWTEST_F_L0(DFXJSNApiTests,DumpHeapSnapshot_001)76 HWTEST_F_L0(DFXJSNApiTests, DumpHeapSnapshot_001)
77 {
78     const int dumpFormat = static_cast<int>(ecmascript::DumpFormat::JSON);
79     const std::string filePath = "DFXJSNApiTests_json_001.heapsnapshot";
80     std::fstream outputString(filePath, std::ios::out);
81     outputString.close();
82     outputString.clear();
83 
84     bool isVmMode = true;
85     bool isPrivate = false;
86     bool captureNumericValue = false;
87     std::fstream inputFile {};
88     EXPECT_TRUE(inputFile.good());
89 
90     DFXJSNApi::DumpHeapSnapshot(vm_, dumpFormat, filePath, isVmMode, isPrivate, captureNumericValue);
91     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 1, "{\"snapshot\":"));
92     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 2, "{\"meta\":"));
93     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 3, "{\"node_fields\":"));
94     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 4, "\"node_types\":"));
95     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 5, "\"edge_fields\":"));
96     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 6, "\"edge_types\":"));
97     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 7, "\"trace_function_info_fields\":"));
98     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 8, "\"trace_node_fields\":"));
99     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 9, "\"sample_fields\":"));
100     EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 10, "\"location_fields\":"));
101     std::remove(filePath.c_str());
102 }
103 
HWTEST_F_L0(DFXJSNApiTests,DumpHeapSnapshot_002)104 HWTEST_F_L0(DFXJSNApiTests, DumpHeapSnapshot_002)
105 {
106     const int dumpFormat = static_cast<int>(ecmascript::DumpFormat::JSON);
107     const std::string filePath = "DFXJSNApiTests_json_002.heapsnapshot";
108     std::fstream outputString(filePath, std::ios::out);
109     outputString.close();
110     outputString.clear();
111 
112     ecmascript::FileStream stream(filePath);
113     EXPECT_TRUE(stream.Good());
114 
115     ecmascript::Progress *progress = nullptr;
116     bool isVmMode = true;
117     bool isPrivate = false;
118     bool captureNumericValue = false;
119     std::fstream fStream {};
120     EXPECT_TRUE(fStream.good());
121 
122     DFXJSNApi::DumpHeapSnapshot(vm_, dumpFormat, &stream, progress, isVmMode, isPrivate, captureNumericValue);
123     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 1, "{\"snapshot\":"));
124     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 2, "{\"meta\":"));
125     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 3, "{\"node_fields\":"));
126     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 4, "\"node_types\":"));
127     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 5, "\"edge_fields\":"));
128     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 6, "\"edge_types\":"));
129     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 7, "\"trace_function_info_fields\":"));
130     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 8, "\"trace_node_fields\":"));
131     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 9, "\"sample_fields\":"));
132     EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 10, "\"location_fields\":"));
133     std::remove(filePath.c_str());
134 }
135 
HWTEST_F_L0(DFXJSNApiTests,BuildNativeAndJsStackTrace)136 HWTEST_F_L0(DFXJSNApiTests, BuildNativeAndJsStackTrace)
137 {
138     bool result = false;
139     std::string stackTraceStr = "stack_trace_str";
140     result = DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
141 #if defined(ENABLE_EXCEPTION_BACKTRACE)
142     EXPECT_FALSE(stackTraceStr.empty());
143     EXPECT_TRUE(result);
144 #else
145     EXPECT_TRUE(stackTraceStr.empty());
146     EXPECT_FALSE(result);
147 #endif
148 }
149 
HWTEST_F_L0(DFXJSNApiTests,BuildJsStackTrace)150 HWTEST_F_L0(DFXJSNApiTests, BuildJsStackTrace)
151 {
152     std::string stackTraceStr = "stack_trace_str";
153     bool result = DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
154 #if defined(ENABLE_EXCEPTION_BACKTRACE)
155     EXPECT_FALSE(stackTraceStr.empty());
156     EXPECT_TRUE(result);
157 #else
158     EXPECT_TRUE(stackTraceStr.empty());
159     EXPECT_FALSE(result);
160 #endif
161 }
162 
HWTEST_F_L0(DFXJSNApiTests,Start_Stop_HeapTracking_001)163 HWTEST_F_L0(DFXJSNApiTests, Start_Stop_HeapTracking_001)
164 {
165     [[maybe_unused]] EcmaHandleScope handleScope(thread_);
166     vm_->SetEnableForceGC(false);
167 
168     auto factory = vm_->GetFactory();
169     bool isVmMode = true;
170     bool traceAllocation = false;
171     double timeInterval = 50; // 50 : time interval 50 ms
172     ecmascript::FileStream *stream = nullptr;
173     bool startResult = false;
174     startResult = DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode, stream, traceAllocation);
175     EXPECT_TRUE(startResult);
176 
177     sleep(1);
178     int count = 300;
179     while (count-- > 0) {
180         JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
181         JSHandle<EcmaString> string = factory->NewFromASCII("Start_Stop_HeapTracking_001_TestString");
182         factory->NewJSString(JSHandle<JSTaggedValue>(string), undefined);
183     }
184     const std::string filePath = "Start_Stop_HeapTracking_001.heaptimeline";
185     std::fstream outputString(filePath, std::ios::out);
186     outputString.close();
187     outputString.clear();
188 
189     bool stopResult = DFXJSNApi::StopHeapTracking(vm_, filePath);
190     EXPECT_TRUE(stopResult);
191 
192     std::fstream inputStream(filePath, std::ios::in);
193     std::string line;
194     std::string emptySample = "\"samples\":";
195     std::string firstSample = "\"samples\":[0, ";
196     bool isFind = false;
197     while (getline(inputStream, line)) {
198         if (line.substr(0U, emptySample.size()) == emptySample) {
199             EXPECT_TRUE(line.substr(0, firstSample.size()) == firstSample);
200             isFind = true;
201         }
202     }
203     EXPECT_TRUE(isFind);
204 
205     inputStream.close();
206     inputStream.clear();
207     std::remove(filePath.c_str());
208     vm_->SetEnableForceGC(true);
209 }
210 
HWTEST_F_L0(DFXJSNApiTests,Start_Stop_HeapTracking_002)211 HWTEST_F_L0(DFXJSNApiTests, Start_Stop_HeapTracking_002)
212 {
213     [[maybe_unused]] EcmaHandleScope handleScope(thread_);
214     vm_->SetEnableForceGC(false);
215 
216     auto factory = vm_->GetFactory();
217     bool isVmMode = true;
218     bool traceAllocation = false;
219     double timeInterval = 50; // 50 : time interval 50 ms
220     ecmascript::FileStream *stream = nullptr;
221     bool startResult = false;
222     startResult = DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode, stream, traceAllocation);
223     EXPECT_TRUE(startResult);
224 
225     sleep(1);
226     int count = 300;
227     while (count-- > 0) {
228         factory->NewJSAsyncFuncObject();
229         factory->NewJSSymbol();
230     }
231     const std::string filePath = "Start_Stop_HeapTracking_002.heaptimeline";
232     std::fstream outputString(filePath, std::ios::out);
233     outputString.close();
234     outputString.clear();
235 
236     ecmascript::FileStream fileStream(filePath);
237     bool stopResult = DFXJSNApi::StopHeapTracking(vm_, &fileStream);
238     EXPECT_TRUE(stopResult);
239 
240     std::fstream inputStream(filePath, std::ios::in);
241     std::string line;
242     std::string emptySample = "\"samples\":";
243     std::string firstSample = "\"samples\":[0, ";
244     bool isFind = false;
245     while (getline(inputStream, line)) {
246         if (line.substr(0U, emptySample.size()) == emptySample) {
247             EXPECT_TRUE(line.substr(0, firstSample.size()) == firstSample);
248             isFind = true;
249         }
250     }
251     EXPECT_TRUE(isFind);
252 
253     inputStream.close();
254     inputStream.clear();
255     std::remove(filePath.c_str());
256     vm_->SetEnableForceGC(true);
257 }
258 
HWTEST_F_L0(DFXJSNApiTests,Start_Stop_RuntimeStat)259 HWTEST_F_L0(DFXJSNApiTests, Start_Stop_RuntimeStat)
260 {
261     EcmaRuntimeStat *ecmaRuntimeStat = vm_->GetJSThread()->GetCurrentEcmaContext()->GetRuntimeStat();
262     EXPECT_TRUE(ecmaRuntimeStat != nullptr);
263 
264     ecmaRuntimeStat->SetRuntimeStatEnabled(false);
265     EXPECT_TRUE(!ecmaRuntimeStat->IsRuntimeStatEnabled());
266 
267     DFXJSNApi::StartRuntimeStat(vm_);
268     EXPECT_TRUE(ecmaRuntimeStat->IsRuntimeStatEnabled());
269 
270     DFXJSNApi::StopRuntimeStat(vm_);
271     EXPECT_TRUE(!ecmaRuntimeStat->IsRuntimeStatEnabled());
272 }
273 
HWTEST_F_L0(DFXJSNApiTests,GetArrayBufferSize_GetHeapTotalSize_GetHeapUsedSize)274 HWTEST_F_L0(DFXJSNApiTests, GetArrayBufferSize_GetHeapTotalSize_GetHeapUsedSize)
275 {
276     auto heap = vm_->GetHeap();
277     size_t arrayBufferSize = DFXJSNApi::GetArrayBufferSize(vm_);
278     size_t expectArrayBufferSize = heap->GetArrayBufferSize();
279     EXPECT_EQ(arrayBufferSize, expectArrayBufferSize);
280 
281     size_t heapTotalSize = DFXJSNApi::GetHeapTotalSize(vm_);
282     size_t expectHeapTotalSize = heap->GetCommittedSize();
283     EXPECT_EQ(heapTotalSize, expectHeapTotalSize);
284 
285     size_t heapUsedSize = DFXJSNApi::GetHeapUsedSize(vm_);
286     size_t expectHeapUsedSize = heap->GetHeapObjectSize();
287     EXPECT_EQ(heapUsedSize, expectHeapUsedSize);
288 }
289 
HWTEST_F_L0(DFXJSNApiTests,NotifyApplicationState)290 HWTEST_F_L0(DFXJSNApiTests, NotifyApplicationState)
291 {
292     auto heap = vm_->GetHeap();
293     auto concurrentMarker = heap->GetConcurrentMarker();
294     auto sweeper = heap->GetSweeper();
295 
296     DFXJSNApi::NotifyApplicationState(vm_, false);
297 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
298     EXPECT_TRUE(!concurrentMarker->IsDisabled());
299 #endif
300     EXPECT_TRUE(!sweeper->IsDisabled());
301 
302     const_cast<ecmascript::Heap *>(heap)->CollectGarbage(TriggerGCType::OLD_GC, GCReason::OTHER);
303     DFXJSNApi::NotifyApplicationState(vm_, true);
304     EXPECT_TRUE(concurrentMarker->IsDisabled());
305     EXPECT_TRUE(sweeper->IsRequestDisabled());
306 }
307 
HWTEST_F_L0(DFXJSNApiTests,NotifyMemoryPressure)308 HWTEST_F_L0(DFXJSNApiTests, NotifyMemoryPressure)
309 {
310     auto heap = vm_->GetHeap();
311     bool inHighMemoryPressure = true;
312     DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
313     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::PRESSURE);
314 
315     inHighMemoryPressure = false;
316     DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
317     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::CONSERVATIVE);
318 }
319 
HWTEST_F_L0(DFXJSNApiTests,BuildJsStackInfoList)320 HWTEST_F_L0(DFXJSNApiTests, BuildJsStackInfoList)
321 {
322     uint32_t hostTid = vm_->GetJSThread()->GetThreadId();
323     std::vector<ecmascript::JsFrameInfo> jsFrameInfo;
324     bool result = DFXJSNApi::BuildJsStackInfoList(vm_, hostTid, jsFrameInfo);
325     EXPECT_FALSE(result);
326 }
327 
HWTEST_F_L0(DFXJSNApiTests,StartSampling)328 HWTEST_F_L0(DFXJSNApiTests, StartSampling)
329 {
330     uint64_t samplingInterval = 32768;
331     bool result = DFXJSNApi::StartSampling(vm_, samplingInterval);
332     EXPECT_TRUE(result);
333     result = DFXJSNApi::StartSampling(vm_, samplingInterval);
334     EXPECT_FALSE(result);
335 }
336 
HWTEST_F_L0(DFXJSNApiTests,StopSampling)337 HWTEST_F_L0(DFXJSNApiTests, StopSampling)
338 {
339     uint64_t samplingInterval = 32768;
340     bool result = DFXJSNApi::StartSampling(vm_, samplingInterval);
341     EXPECT_TRUE(result);
342     DFXJSNApi::StopSampling(vm_);
343     result = DFXJSNApi::StartSampling(vm_, samplingInterval);
344     EXPECT_TRUE(result);
345 }
346 
HWTEST_F_L0(DFXJSNApiTests,GetAllocationProfile)347 HWTEST_F_L0(DFXJSNApiTests, GetAllocationProfile)
348 {
349     const SamplingInfo *result = DFXJSNApi::GetAllocationProfile(vm_);
350     EXPECT_TRUE(result == nullptr);
351     uint64_t samplingInterval = 32768;
352     DFXJSNApi::StartSampling(vm_, samplingInterval);
353     result = DFXJSNApi::GetAllocationProfile(vm_);
354     EXPECT_TRUE(result != nullptr);
355 }
356 } // namespace panda::test
357