1 /*
2 * Copyright (c) 2022 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_->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 std::fstream inputFile {};
87 EXPECT_TRUE(inputFile.good());
88
89 DFXJSNApi::DumpHeapSnapshot(vm_, dumpFormat, filePath, isVmMode, isPrivate);
90 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 1, "{\"snapshot\":"));
91 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 2, "{\"meta\":"));
92 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 3, "{\"node_fields\":"));
93 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 4, "\"node_types\":"));
94 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 5, "\"edge_fields\":"));
95 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 6, "\"edge_types\":"));
96 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 7, "\"trace_function_info_fields\":"));
97 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 8, "\"trace_node_fields\":"));
98 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 9, "\"sample_fields\":"));
99 EXPECT_TRUE(MatchJSONLineHeader(inputFile, filePath, 10, "\"location_fields\":"));
100 std::remove(filePath.c_str());
101 }
102
HWTEST_F_L0(DFXJSNApiTests,DumpHeapSnapshot_002)103 HWTEST_F_L0(DFXJSNApiTests, DumpHeapSnapshot_002)
104 {
105 const int dumpFormat = static_cast<int>(ecmascript::DumpFormat::JSON);
106 const std::string filePath = "DFXJSNApiTests_json_002.heapsnapshot";
107 std::fstream outputString(filePath, std::ios::out);
108 outputString.close();
109 outputString.clear();
110
111 ecmascript::FileStream stream(filePath);
112 EXPECT_TRUE(stream.Good());
113
114 ecmascript::Progress *progress = nullptr;
115 bool isVmMode = true;
116 bool isPrivate = false;
117 std::fstream fStream {};
118 EXPECT_TRUE(fStream.good());
119
120 DFXJSNApi::DumpHeapSnapshot(vm_, dumpFormat, &stream, progress, isVmMode, isPrivate);
121 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 1, "{\"snapshot\":"));
122 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 2, "{\"meta\":"));
123 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 3, "{\"node_fields\":"));
124 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 4, "\"node_types\":"));
125 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 5, "\"edge_fields\":"));
126 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 6, "\"edge_types\":"));
127 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 7, "\"trace_function_info_fields\":"));
128 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 8, "\"trace_node_fields\":"));
129 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 9, "\"sample_fields\":"));
130 EXPECT_TRUE(MatchJSONLineHeader(fStream, filePath, 10, "\"location_fields\":"));
131 std::remove(filePath.c_str());
132 }
133
HWTEST_F_L0(DFXJSNApiTests,BuildNativeAndJsStackTrace)134 HWTEST_F_L0(DFXJSNApiTests, BuildNativeAndJsStackTrace)
135 {
136 bool result = false;
137 std::string stackTraceStr = "stack_trace_str";
138 result = DFXJSNApi::BuildNativeAndJsStackTrace(vm_, stackTraceStr);
139 EXPECT_TRUE(stackTraceStr.empty());
140 EXPECT_FALSE(result);
141 }
142
HWTEST_F_L0(DFXJSNApiTests,BuildJsStackTrace)143 HWTEST_F_L0(DFXJSNApiTests, BuildJsStackTrace)
144 {
145 std::string stackTraceStr = "stack_trace_str";
146 bool result = DFXJSNApi::BuildJsStackTrace(vm_, stackTraceStr);
147 EXPECT_TRUE(stackTraceStr.empty());
148 EXPECT_FALSE(result);
149 }
150
HWTEST_F_L0(DFXJSNApiTests,Start_Stop_HeapTracking_001)151 HWTEST_F_L0(DFXJSNApiTests, Start_Stop_HeapTracking_001)
152 {
153 [[maybe_unused]] EcmaHandleScope handleScope(thread_);
154 vm_->SetEnableForceGC(false);
155
156 auto factory = vm_->GetFactory();
157 bool isVmMode = true;
158 bool traceAllocation = false;
159 double timeInterval = 50; // 50 : time interval 50 ms
160 ecmascript::FileStream *stream = nullptr;
161 bool startResult = false;
162 startResult = DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode, stream, traceAllocation);
163 EXPECT_TRUE(startResult);
164
165 sleep(1);
166 int count = 300;
167 while (count-- > 0) {
168 JSHandle<EcmaString> string = factory->NewFromASCII("Start_Stop_HeapTracking_001_TestString");
169 factory->NewJSString(JSHandle<JSTaggedValue>(string));
170 }
171 const std::string filePath = "Start_Stop_HeapTracking_001.heaptimeline";
172 std::fstream outputString(filePath, std::ios::out);
173 outputString.close();
174 outputString.clear();
175
176 bool stopResult = DFXJSNApi::StopHeapTracking(vm_, filePath);
177 EXPECT_TRUE(stopResult);
178
179 std::fstream inputStream(filePath, std::ios::in);
180 std::string line;
181 std::string emptySample = "\"samples\":";
182 std::string firstSample = "\"samples\":[0, ";
183 bool isFind = false;
184 while (getline(inputStream, line)) {
185 if (line.substr(0U, emptySample.size()) == emptySample) {
186 EXPECT_TRUE(line.substr(0, firstSample.size()) == firstSample);
187 isFind = true;
188 }
189 }
190 EXPECT_TRUE(isFind);
191
192 inputStream.close();
193 inputStream.clear();
194 std::remove(filePath.c_str());
195 vm_->SetEnableForceGC(true);
196 }
197
HWTEST_F_L0(DFXJSNApiTests,Start_Stop_HeapTracking_002)198 HWTEST_F_L0(DFXJSNApiTests, Start_Stop_HeapTracking_002)
199 {
200 [[maybe_unused]] EcmaHandleScope handleScope(thread_);
201 vm_->SetEnableForceGC(false);
202
203 auto factory = vm_->GetFactory();
204 bool isVmMode = true;
205 bool traceAllocation = false;
206 double timeInterval = 50; // 50 : time interval 50 ms
207 ecmascript::FileStream *stream = nullptr;
208 bool startResult = false;
209 startResult = DFXJSNApi::StartHeapTracking(vm_, timeInterval, isVmMode, stream, traceAllocation);
210 EXPECT_TRUE(startResult);
211
212 sleep(1);
213 int count = 300;
214 while (count-- > 0) {
215 factory->NewJSAsyncFuncObject();
216 factory->NewJSSymbol();
217 }
218 const std::string filePath = "Start_Stop_HeapTracking_002.heaptimeline";
219 std::fstream outputString(filePath, std::ios::out);
220 outputString.close();
221 outputString.clear();
222
223 ecmascript::FileStream fileStream(filePath);
224 bool stopResult = DFXJSNApi::StopHeapTracking(vm_, &fileStream);
225 EXPECT_TRUE(stopResult);
226
227 std::fstream inputStream(filePath, std::ios::in);
228 std::string line;
229 std::string emptySample = "\"samples\":";
230 std::string firstSample = "\"samples\":[0, ";
231 bool isFind = false;
232 while (getline(inputStream, line)) {
233 if (line.substr(0U, emptySample.size()) == emptySample) {
234 EXPECT_TRUE(line.substr(0, firstSample.size()) == firstSample);
235 isFind = true;
236 }
237 }
238 EXPECT_TRUE(isFind);
239
240 inputStream.close();
241 inputStream.clear();
242 std::remove(filePath.c_str());
243 vm_->SetEnableForceGC(true);
244 }
245
HWTEST_F_L0(DFXJSNApiTests,Start_Stop_RuntimeStat)246 HWTEST_F_L0(DFXJSNApiTests, Start_Stop_RuntimeStat)
247 {
248 EcmaRuntimeStat *ecmaRuntimeStat = vm_->GetRuntimeStat();
249 EXPECT_TRUE(ecmaRuntimeStat != nullptr);
250
251 ecmaRuntimeStat->SetRuntimeStatEnabled(false);
252 EXPECT_TRUE(!ecmaRuntimeStat->IsRuntimeStatEnabled());
253
254 DFXJSNApi::StartRuntimeStat(vm_);
255 EXPECT_TRUE(ecmaRuntimeStat->IsRuntimeStatEnabled());
256
257 DFXJSNApi::StopRuntimeStat(vm_);
258 EXPECT_TRUE(!ecmaRuntimeStat->IsRuntimeStatEnabled());
259 }
260
HWTEST_F_L0(DFXJSNApiTests,GetArrayBufferSize_GetHeapTotalSize_GetHeapUsedSize)261 HWTEST_F_L0(DFXJSNApiTests, GetArrayBufferSize_GetHeapTotalSize_GetHeapUsedSize)
262 {
263 auto heap = vm_->GetHeap();
264 size_t arrayBufferSize = DFXJSNApi::GetArrayBufferSize(vm_);
265 size_t expectArrayBufferSize = heap->GetArrayBufferSize();
266 EXPECT_EQ(arrayBufferSize, expectArrayBufferSize);
267
268 size_t heapTotalSize = DFXJSNApi::GetHeapTotalSize(vm_);
269 size_t expectHeapTotalSize = heap->GetCommittedSize();
270 EXPECT_EQ(heapTotalSize, expectHeapTotalSize);
271
272 size_t heapUsedSize = DFXJSNApi::GetHeapUsedSize(vm_);
273 size_t expectHeapUsedSize = heap->GetHeapObjectSize();
274 EXPECT_EQ(heapUsedSize, expectHeapUsedSize);
275 }
276
HWTEST_F_L0(DFXJSNApiTests,NotifyApplicationState)277 HWTEST_F_L0(DFXJSNApiTests, NotifyApplicationState)
278 {
279 auto heap = vm_->GetHeap();
280 auto concurrentMarker = heap->GetConcurrentMarker();
281 auto sweeper = heap->GetSweeper();
282
283 DFXJSNApi::NotifyApplicationState(vm_, false);
284 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
285 EXPECT_TRUE(!concurrentMarker->IsDisabled());
286 #endif
287 EXPECT_TRUE(!sweeper->IsDisabled());
288
289 bool fullGC = false;
290 sweeper->Sweep(fullGC);
291 DFXJSNApi::NotifyApplicationState(vm_, true);
292 EXPECT_TRUE(concurrentMarker->IsDisabled());
293 EXPECT_TRUE(sweeper->IsRequestDisabled());
294 }
295
HWTEST_F_L0(DFXJSNApiTests,NotifyMemoryPressure)296 HWTEST_F_L0(DFXJSNApiTests, NotifyMemoryPressure)
297 {
298 auto heap = vm_->GetHeap();
299 bool inHighMemoryPressure = true;
300 DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
301 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::PRESSURE);
302
303 inHighMemoryPressure = false;
304 DFXJSNApi::NotifyMemoryPressure(vm_, inHighMemoryPressure);
305 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::CONSERVATIVE);
306 }
307
HWTEST_F_L0(DFXJSNApiTests,BuildJsStackInfoList)308 HWTEST_F_L0(DFXJSNApiTests, BuildJsStackInfoList)
309 {
310 uint32_t hostTid = vm_->GetJSThread()->GetThreadId();
311 std::vector<ecmascript::JsFrameInfo> jsFrameInfo;
312 bool result = DFXJSNApi::BuildJsStackInfoList(vm_, hostTid, jsFrameInfo);
313 EXPECT_FALSE(result);
314 }
315 } // namespace panda::test
316