1 /*
2 * Copyright (c) 2024 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 <cstdio>
17
18 #include "ecmascript/dfx/cpu_profiler/samples_record.h"
19 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda::ecmascript;
23
24 namespace panda::ecmascript {
25 class SamplesRecordFriendTest {
26 public:
SamplesRecordFriendTest()27 SamplesRecordFriendTest() : samples_record() {}
28
AddRunningStateTest(char * functionName,RunningState state,kungfu::DeoptType type)29 std::string AddRunningStateTest(char *functionName, RunningState state, kungfu::DeoptType type)
30 {
31 return samples_record.AddRunningState(functionName, state, type);
32 }
33
SetEnableVMTag(bool flag)34 void SetEnableVMTag(bool flag)
35 {
36 samples_record.SetEnableVMTag(flag);
37 }
38
StatisticStateTimeTest(int timeDelta,RunningState state)39 void StatisticStateTimeTest(int timeDelta, RunningState state)
40 {
41 samples_record.StatisticStateTime(timeDelta, state);
42 }
43
PushNapiStackInfoTest(const FrameInfoTemp & frameInfoTemp)44 bool PushNapiStackInfoTest(const FrameInfoTemp &frameInfoTemp)
45 {
46 return samples_record.PushNapiStackInfo(frameInfoTemp);
47 }
48
NapiFrameInfoTempToMapTest()49 void NapiFrameInfoTempToMapTest()
50 {
51 samples_record.NapiFrameInfoTempToMap();
52 }
53
TranslateUrlPositionBySourceMapTest(struct FrameInfo & codeEntry)54 void TranslateUrlPositionBySourceMapTest(struct FrameInfo &codeEntry)
55 {
56 samples_record.TranslateUrlPositionBySourceMap(codeEntry);
57 }
58
sourceMapTranslateCallbackTest(SourceMapTranslateCallback sourceMapTranslateCallback_)59 void sourceMapTranslateCallbackTest(SourceMapTranslateCallback sourceMapTranslateCallback_)
60 {
61 samples_record.sourceMapTranslateCallback_ = sourceMapTranslateCallback_;
62 }
63
GetProfileInfoTest()64 std::unique_ptr<ProfileInfo> GetProfileInfoTest()
65 {
66 return std::move(samples_record.profileInfo_);
67 }
68
69 private:
70 SamplesRecord samples_record;
71 };
72 }
73
74 namespace panda::test {
75 class SamplesRecordTest : public testing::Test {
76 public:
SetUpTestCase()77 static void SetUpTestCase()
78 {
79 GTEST_LOG_(INFO) << "SetUpTestCase";
80 }
81
TearDownTestCase()82 static void TearDownTestCase()
83 {
84 GTEST_LOG_(INFO) << "TearDownCase";
85 }
86
SetUp()87 void SetUp() override
88 {
89 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
90 instance->SetEnableForceGC(false);
91 }
92
TearDown()93 void TearDown() override
94 {
95 TestHelper::DestroyEcmaVMWithScope(instance, scope);
96 }
97
98 EcmaVM *instance {nullptr};
99 EcmaHandleScope *scope {nullptr};
100 JSThread *thread {nullptr};
101 };
102
HWTEST_F_L0(SamplesRecordTest,AddRunningStateTest)103 HWTEST_F_L0(SamplesRecordTest, AddRunningStateTest)
104 {
105 SamplesRecordFriendTest samplesRecord;
106 char funcName[] = "testFunction";
107 std::string result = samplesRecord.AddRunningStateTest(funcName, RunningState::AINT_D,
108 kungfu::DeoptType::NONE);
109 EXPECT_EQ(result, "testFunction(AINT-D)");
110
111 result = samplesRecord.AddRunningStateTest(funcName, RunningState::GC,
112 kungfu::DeoptType::NOTDOUBLE1);
113 EXPECT_EQ(result, "testFunction(GC)");
114
115 result = samplesRecord.AddRunningStateTest(funcName, RunningState::CINT,
116 kungfu::DeoptType::NOTDOUBLE1);
117 EXPECT_EQ(result, "testFunction");
118
119 result = samplesRecord.AddRunningStateTest(funcName, RunningState::AINT,
120 kungfu::DeoptType::NOTDOUBLE1);
121 EXPECT_EQ(result, "testFunction");
122
123 result = samplesRecord.AddRunningStateTest(funcName, RunningState::AOT,
124 kungfu::DeoptType::NOTDOUBLE1);
125 EXPECT_EQ(result, "testFunction");
126
127 result = samplesRecord.AddRunningStateTest(funcName, RunningState::BUILTIN,
128 kungfu::DeoptType::NOTDOUBLE1);
129 EXPECT_EQ(result, "testFunction(BUILTIN)");
130
131 result = samplesRecord.AddRunningStateTest(funcName, RunningState::NAPI,
132 kungfu::DeoptType::NOTDOUBLE1);
133 EXPECT_EQ(result, "testFunction(NAPI)");
134
135 result = samplesRecord.AddRunningStateTest(funcName, RunningState::ARKUI_ENGINE,
136 kungfu::DeoptType::NOTDOUBLE1);
137 EXPECT_EQ(result, "testFunction(ARKUI_ENGINE)");
138
139 result = samplesRecord.AddRunningStateTest(funcName, RunningState::RUNTIME,
140 kungfu::DeoptType::NOTDOUBLE1);
141 EXPECT_EQ(result, "testFunction");
142
143 result = samplesRecord.AddRunningStateTest(funcName, RunningState::JIT,
144 kungfu::DeoptType::NOTDOUBLE1);
145 EXPECT_EQ(result, "testFunction(JIT)");
146
147 samplesRecord.SetEnableVMTag(true);
148 result = samplesRecord.AddRunningStateTest(funcName, RunningState::CINT,
149 kungfu::DeoptType::NOTDOUBLE1);
150 EXPECT_EQ(result, "testFunction(CINT)");
151
152 result = samplesRecord.AddRunningStateTest(funcName, RunningState::AINT,
153 kungfu::DeoptType::NOTDOUBLE1);
154 EXPECT_EQ(result, "testFunction(AINT)");
155
156 result = samplesRecord.AddRunningStateTest(funcName, RunningState::AOT,
157 kungfu::DeoptType::NOTDOUBLE1);
158 EXPECT_EQ(result, "testFunction(AOT)");
159
160 result = samplesRecord.AddRunningStateTest(funcName, RunningState::RUNTIME,
161 kungfu::DeoptType::NOTDOUBLE1);
162 EXPECT_EQ(result, "testFunction(RUNTIME)");
163
164 result = samplesRecord.AddRunningStateTest(funcName, RunningState::AINT_D,
165 kungfu::DeoptType::NOTINT1);
166 EXPECT_EQ(result, "testFunction(AINT-D)(DEOPT:NotInt1)");
167 }
168
HWTEST_F_L0(SamplesRecordTest,StatisticStateTimeTest)169 HWTEST_F_L0(SamplesRecordTest, StatisticStateTimeTest)
170 {
171 SamplesRecordFriendTest samplesRecord;
172 samplesRecord.StatisticStateTimeTest(100, RunningState::AINT_D);
173 samplesRecord.StatisticStateTimeTest(101, RunningState::GC);
174 samplesRecord.StatisticStateTimeTest(102, RunningState::CINT);
175 samplesRecord.StatisticStateTimeTest(103, RunningState::AINT);
176 samplesRecord.StatisticStateTimeTest(104, RunningState::AOT);
177 samplesRecord.StatisticStateTimeTest(105, RunningState::BUILTIN);
178 samplesRecord.StatisticStateTimeTest(106, RunningState::NAPI);
179 samplesRecord.StatisticStateTimeTest(107, RunningState::ARKUI_ENGINE);
180 samplesRecord.StatisticStateTimeTest(108, RunningState::RUNTIME);
181 samplesRecord.StatisticStateTimeTest(109, RunningState::JIT);
182
183 std::unique_ptr<ProfileInfo> profileInfo = samplesRecord.GetProfileInfoTest();
184 EXPECT_EQ(profileInfo->asmInterpreterDeoptTime, 100);
185 EXPECT_EQ(profileInfo->gcTime, 101);
186 EXPECT_EQ(profileInfo->cInterpreterTime, 102);
187 EXPECT_EQ(profileInfo->asmInterpreterTime, 103);
188 EXPECT_EQ(profileInfo->aotTime, 104);
189 EXPECT_EQ(profileInfo->builtinTime, 105);
190 EXPECT_EQ(profileInfo->napiTime, 106);
191 EXPECT_EQ(profileInfo->arkuiEngineTime, 107);
192 EXPECT_EQ(profileInfo->runtimeTime, 108);
193 EXPECT_EQ(profileInfo->jitTime, 109);
194 }
195
HWTEST_F_L0(SamplesRecordTest,PushStackTest)196 HWTEST_F_L0(SamplesRecordTest, PushStackTest)
197 {
198 SamplesRecord record;
199 MethodKey key;
200
201 for (size_t i = 0; i < MAX_STACK_SIZE; ++i) {
202 key.lineNumber = static_cast<int>(i);
203 EXPECT_TRUE(record.PushFrameStack(key));
204 }
205 EXPECT_FALSE(record.PushFrameStack(key));
206
207 for (size_t i = 0; i < MAX_STACK_SIZE; ++i) {
208 key.lineNumber = static_cast<int>(i);
209 EXPECT_TRUE(record.PushNapiFrameStack(key));
210 }
211 EXPECT_FALSE(record.PushNapiFrameStack(key));
212
213 FrameInfoTemp frameInfoTemp;
214 for (size_t i = 0; i < MAX_STACK_SIZE; ++i) {
215 frameInfoTemp.lineNumber = static_cast<int>(i);
216 EXPECT_TRUE(record.PushStackInfo(frameInfoTemp));
217 }
218 EXPECT_FALSE(record.PushStackInfo(frameInfoTemp));
219
220 for (size_t i = 0; i < MAX_STACK_SIZE; ++i) {
221 frameInfoTemp.lineNumber = static_cast<int>(i);
222 EXPECT_TRUE(record.PushNapiStackInfo(frameInfoTemp));
223 }
224 EXPECT_FALSE(record.PushNapiStackInfo(frameInfoTemp));
225 }
226
HWTEST_F_L0(SamplesRecordTest,GetModuleNameTest)227 HWTEST_F_L0(SamplesRecordTest, GetModuleNameTest)
228 {
229 SamplesRecord record;
230
231 char input1[] = "/path/to/module@version";
232 EXPECT_EQ(record.GetModuleName(input1), "module");
233
234 char input2[] = "/path/to/module";
235 EXPECT_EQ(record.GetModuleName(input2), "");
236
237 char input3[] = "module@version";
238 EXPECT_EQ(record.GetModuleName(input3), "");
239 }
240
HWTEST_F_L0(SamplesRecordTest,NapiFrameInfoTempToMapTest)241 HWTEST_F_L0(SamplesRecordTest, NapiFrameInfoTempToMapTest)
242 {
243 SamplesRecordFriendTest samplesRecord;
244 samplesRecord.NapiFrameInfoTempToMapTest();
245 FrameInfoTemp frameInfoTemp;
246 frameInfoTemp.lineNumber = static_cast<int>(5);
247 samplesRecord.PushNapiStackInfoTest(frameInfoTemp);
248 samplesRecord.NapiFrameInfoTempToMapTest();
249 }
250
HWTEST_F_L0(SamplesRecordTest,TranslateUrlPositionBySourceMapTest)251 HWTEST_F_L0(SamplesRecordTest, TranslateUrlPositionBySourceMapTest)
252 {
253 SamplesRecordFriendTest samplesRecord;
254 FrameInfo entry1;
255 SourceMapTranslateCallback sourceMapTranslateCallback_ = [](const std::string&, int, int,
256 std::string) { return true; };
257 samplesRecord.sourceMapTranslateCallbackTest(sourceMapTranslateCallback_);
258 samplesRecord.TranslateUrlPositionBySourceMapTest(entry1);
259 EXPECT_EQ(entry1.url, "");
260
261 FrameInfo entry2;
262 entry2.url = "some_url.js";
263 entry2.packageName = "name";
264 sourceMapTranslateCallback_ = [](const std::string&, int, int, std::string) { return true; };
265 samplesRecord.sourceMapTranslateCallbackTest(sourceMapTranslateCallback_);
266 samplesRecord.TranslateUrlPositionBySourceMapTest(entry2);
267 EXPECT_EQ(entry2.url, "some_url.js");
268
269 FrameInfo entry3;
270 entry3.url = "path/to/_.js";
271 entry3.packageName = "name";
272 sourceMapTranslateCallback_ = [](const std::string&, int, int, std::string) { return false; };
273 samplesRecord.sourceMapTranslateCallbackTest(sourceMapTranslateCallback_);
274 samplesRecord.TranslateUrlPositionBySourceMapTest(entry3);
275 EXPECT_EQ(entry3.url, "path/to/_.js");
276
277 FrameInfo entry4;
278 entry4.url = "entry/some_key.ets";
279 entry4.packageName = "name";
280 sourceMapTranslateCallback_ = [](const std::string&, int, int, std::string) { return false; };
281 samplesRecord.sourceMapTranslateCallbackTest(sourceMapTranslateCallback_);
282 samplesRecord.TranslateUrlPositionBySourceMapTest(entry4);
283 EXPECT_EQ(entry4.url, "entry/build/default/cache/default/default@CompileArkTS/esmodule/debug/some_key.js");
284
285 FrameInfo entry5;
286 entry5.url = "entry/some_key.other";
287 entry5.packageName = "name";
288 sourceMapTranslateCallback_ = [](const std::string&, int, int, std::string) { return false; };
289 samplesRecord.sourceMapTranslateCallbackTest(sourceMapTranslateCallback_);
290 samplesRecord.TranslateUrlPositionBySourceMapTest(entry5);
291 EXPECT_EQ(entry5.url, "entry/some_key.other");
292
293 FrameInfo entry6;
294 entry6.url = "other/path.js";
295 entry6.packageName = "name";
296 sourceMapTranslateCallback_ = [](const std::string&, int, int, std::string) { return false; };
297 samplesRecord.sourceMapTranslateCallbackTest(sourceMapTranslateCallback_);
298 samplesRecord.TranslateUrlPositionBySourceMapTest(entry6);
299 EXPECT_EQ(entry6.url, "other/path.js");
300 }
301 } // namespace panda::test