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/cpu_profiler.h"
19 #include "ecmascript/tests/test_helper.h"
20 
21 using namespace panda::ecmascript;
22 
23 namespace panda::ecmascript {
24 class CpuProfilerFriendTest {
25 public:
CpuProfilerFriendTest(const EcmaVM *vm, const int interval)26     explicit CpuProfilerFriendTest(const EcmaVM *vm, const int interval) : cpu_profiler(vm, interval) {}
27 
SetIsProfiling(bool isProfiling)28     void SetIsProfiling(bool isProfiling)
29     {
30         cpu_profiler.isProfiling_ = isProfiling;
31     }
32 
SetOutToFile(bool outToFile)33     void SetOutToFile(bool outToFile)
34     {
35         cpu_profiler.outToFile_ = outToFile;
36     }
37 
SetInterval(uint32_t intervalTest)38     void SetInterval(uint32_t intervalTest)
39     {
40         cpu_profiler.interval_ = intervalTest;
41     }
42 
StartCpuProfilerForInfoTest()43     bool StartCpuProfilerForInfoTest()
44     {
45         return cpu_profiler.StartCpuProfilerForInfo();
46     }
47 
StopCpuProfilerForInfoTest(std::unique_ptr<struct ProfileInfo> &profileInfo)48     bool StopCpuProfilerForInfoTest(std::unique_ptr<struct ProfileInfo> &profileInfo)
49     {
50         return cpu_profiler.StopCpuProfilerForInfo(profileInfo);
51     }
52 
StartCpuProfilerForFileTest(const std::string &fileName)53     bool StartCpuProfilerForFileTest(const std::string &fileName)
54     {
55         return cpu_profiler.StartCpuProfilerForFile(fileName);
56     }
57 
StopCpuProfilerForFileTest()58     bool StopCpuProfilerForFileTest()
59     {
60         return cpu_profiler.StopCpuProfilerForFile();
61     }
62 
GetStackBeforeCallNapiTest(JSThread *thread)63     bool GetStackBeforeCallNapiTest(JSThread *thread)
64     {
65         return cpu_profiler.GetStackBeforeCallNapi(thread);
66     }
67 
68 private:
69     CpuProfiler cpu_profiler;
70 };
71 }
72 
73 namespace panda::test {
74 class CpuProfilerTest : public testing::Test {
75 public:
SetUpTestCase()76     static void SetUpTestCase()
77     {
78         GTEST_LOG_(INFO) << "SetUpTestCase";
79     }
80 
TearDownTestCase()81     static void TearDownTestCase()
82     {
83         GTEST_LOG_(INFO) << "TearDownCase";
84     }
85 
86     void SetUp() override
87     {
88         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
89         instance->SetEnableForceGC(false);
90     }
91 
92     void TearDown() override
93     {
94         TestHelper::DestroyEcmaVMWithScope(instance, scope);
95     }
96 
97     EcmaVM *instance {nullptr};
98     EcmaHandleScope *scope {nullptr};
99     JSThread *thread {nullptr};
100 };
101 
HWTEST_F_L0(CpuProfilerTest, TestStopCpuProfilerForFile)102 HWTEST_F_L0(CpuProfilerTest, TestStopCpuProfilerForFile)
103 {
104     int interval = 1;
105     bool ret;
106     CpuProfilerFriendTest cpuProfilerFriend(instance, interval);
107     ret = cpuProfilerFriend.StopCpuProfilerForFileTest();
108     EXPECT_TRUE(ret);
109 
110     cpuProfilerFriend.SetIsProfiling(true);
111     cpuProfilerFriend.StartCpuProfilerForInfoTest();
112     ret = cpuProfilerFriend.StopCpuProfilerForFileTest();
113     EXPECT_FALSE(ret);
114 }
115 
HWTEST_F_L0(CpuProfilerTest, TestStartCpuProfilerForFile)116 HWTEST_F_L0(CpuProfilerTest, TestStartCpuProfilerForFile)
117 {
118     int interval = 1;
119     bool ret;
120     CpuProfilerFriendTest cpuProfilerFriend(instance, interval);
121     std::string filename1("__CpuprofilerTest.abc");
122     std::string filename2("");
123     std::string filename3(PATH_MAX + 1, ' ');
124 
125     ret = cpuProfilerFriend.StartCpuProfilerForFileTest(filename1);
126     EXPECT_FALSE(ret);
127     ret = cpuProfilerFriend.StartCpuProfilerForFileTest(filename2);
128     EXPECT_FALSE(ret);
129     ret = cpuProfilerFriend.StartCpuProfilerForFileTest(filename3);
130     EXPECT_FALSE(ret);
131 
132     cpuProfilerFriend.SetIsProfiling(true);
133     ret = cpuProfilerFriend.StartCpuProfilerForFileTest(filename1);
134     EXPECT_FALSE(ret);
135 }
136 
HWTEST_F_L0(CpuProfilerTest, TestStopCpuProfilerForInfo)137 HWTEST_F_L0(CpuProfilerTest, TestStopCpuProfilerForInfo)
138 {
139     int interval = 1;
140     bool ret;
141     CpuProfilerFriendTest cpuProfilerFriend(instance, interval);
142     std::unique_ptr<ProfileInfo> profileInfo;
143 
144     ret = cpuProfilerFriend.StopCpuProfilerForInfoTest(profileInfo);
145     EXPECT_TRUE(ret);
146 
147     cpuProfilerFriend.StartCpuProfilerForInfoTest();
148     ret = cpuProfilerFriend.StopCpuProfilerForInfoTest(profileInfo);
149     EXPECT_TRUE(ret);
150 
151     cpuProfilerFriend.SetIsProfiling(true);
152     cpuProfilerFriend.SetOutToFile(true);
153     ret = cpuProfilerFriend.StopCpuProfilerForInfoTest(profileInfo);
154     EXPECT_FALSE(ret);
155 }
156 
HWTEST_F_L0(CpuProfilerTest, TestGetStackBeforeCallNapi)157 HWTEST_F_L0(CpuProfilerTest, TestGetStackBeforeCallNapi)
158 {
159     uint32_t interval = 100;
160     CpuProfilerFriendTest cpuProfilerFriend(instance, interval);
161 
162     bool flag = cpuProfilerFriend.GetStackBeforeCallNapiTest(thread);
163     EXPECT_TRUE(flag);
164 
165     cpuProfilerFriend.SetInterval(UINT32_MAX);
166     flag = cpuProfilerFriend.GetStackBeforeCallNapiTest(thread);
167     EXPECT_FALSE(flag);
168 }
169 
HWTEST_F_L0(CpuProfilerTest, TestCpuProfilerHasSameName)170 HWTEST_F_L0(CpuProfilerTest, TestCpuProfilerHasSameName)
171 {
172     int interval = 500;
173 
174     bool res = DFXJSNApi::StartCpuProfilerForInfo(instance, interval);
175     EXPECT_TRUE(res);
176     // The cpuprofiler_1.js only support test A->B->C, not support test A->C, B->C
177     std::string fileName = DEBUGGER_ABC_DIR "cpuprofiler_1.abc";
178     std::string entryPoint = "cpuprofiler_1";
179     res = JSNApi::Execute(instance, fileName, entryPoint);
180     ASSERT_TRUE(res);
181     std::unique_ptr<ProfileInfo> profileInfo = DFXJSNApi::StopCpuProfilerForInfo(instance);
182     size_t nodesLen = profileInfo->nodeCount;
183     std::unordered_set<std::string> functionNames;
184     // Check if the function has multiple nodes
185     for (size_t i = 0; i < nodesLen; ++i) {
186         const auto &cpuProfileNode = profileInfo->nodes[i];
187         std::string functionName = cpuProfileNode.codeEntry.functionName;
188         auto node = functionNames.find(functionName);
189         if (node == functionNames.end()) {
190             functionNames.insert(functionName);
191         } else {
192             res = false;
193             break;
194         }
195     }
196     ASSERT_TRUE(res);
197 }
198 }  // namespace panda::test