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