1 /*
2 * Copyright (c) 2021 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 "perf_events_test.h"
17
18 #include <chrono>
19 #include <cinttypes>
20 #include <cstdlib>
21 #include <thread>
22 #include <unistd.h>
23
24 #include "debug_logger.h"
25 #include "utilities.h"
26
27 using namespace testing::ext;
28 using namespace std;
29 using namespace OHOS::HiviewDFX;
30
31 namespace OHOS {
32 namespace Developtools {
33 namespace HiPerf {
34 class PerfEventsTest : public testing::Test {
35 public:
36 static void SetUpTestCase(void);
37 static void TearDownTestCase(void);
38 void SetUp();
39 void TearDown();
40
41 static void TestCodeThread(void);
42 static void RunTestThreads(std::vector<std::thread> &threads);
43 static void SetAllConfig(PerfEvents &event);
44 static bool RecordCount(std::unique_ptr<PerfEventRecord> record);
45 static void StatCount(
46 const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &countEvents);
47
48 static constexpr int TEST_CODE_MEM_FILE_SIZE = 1024;
49 static constexpr auto TEST_CODE_SLEEP_BEFORE_RUN = 500ms;
50 static constexpr auto TEST_CODE_SLEEP_AFTER_RUN = 1000ms;
51 static constexpr int TEST_CODE_RUN_TIME = 10240;
52 static constexpr int DOUBLE = 2;
53 static constexpr int TRIPLE = 3;
54 static constexpr auto TEST_TIME = 3s;
55 static constexpr auto DEFAULT_TRACKING_TIME = 1000;
56 static constexpr auto DEFAULT_STAT_REPORT_TIME = 500;
57 static constexpr auto DEFAULT_SAMPLE_MMAPAGE = 256;
58
59 static uint64_t g_recordCount;
60 static uint64_t g_statCount;
61 };
62
SetUpTestCase()63 void PerfEventsTest::SetUpTestCase() {}
64
TearDownTestCase()65 void PerfEventsTest::TearDownTestCase() {}
66
SetUp()67 void PerfEventsTest::SetUp() {}
68
TearDown()69 void PerfEventsTest::TearDown() {}
70
71 uint64_t PerfEventsTest::g_recordCount = 0;
72 uint64_t PerfEventsTest::g_statCount = 0;
73
RecordCount(std::unique_ptr<PerfEventRecord> record)74 bool PerfEventsTest::RecordCount(std::unique_ptr<PerfEventRecord> record)
75 {
76 g_recordCount++;
77 return true;
78 }
79
StatCount(const std::map<std::string,std::unique_ptr<PerfEvents::CountEvent>> & countEvents)80 void PerfEventsTest::StatCount(
81 const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &countEvents)
82 {
83 g_statCount++;
84 }
85
TestCodeThread()86 void PerfEventsTest::TestCodeThread()
87 {
88 std::vector<std::unique_ptr<char[]>> mems;
89 int tid = gettid();
90 printf("%s:%d ++\n", __FUNCTION__, tid);
91 for (int n = 0; n < TRIPLE; n++) {
92 std::this_thread::sleep_for(TEST_CODE_SLEEP_BEFORE_RUN);
93 constexpr size_t memSize {TEST_CODE_MEM_FILE_SIZE};
94 for (int i = 0; i < TEST_CODE_RUN_TIME; i++) {
95 if (i % DOUBLE == 0) {
96 mems.push_back(std::make_unique<char[]>(memSize));
97 } else {
98 mems.push_back(std::make_unique<char[]>(memSize * DOUBLE));
99 }
100 }
101
102 for (int i = 0; i < TEST_CODE_RUN_TIME; i++) {
103 mems.pop_back();
104 }
105
106 std::this_thread::sleep_for(TEST_CODE_SLEEP_AFTER_RUN);
107 }
108 printf("%s:%d --\n", __FUNCTION__, tid);
109 }
110
RunTestThreads(std::vector<std::thread> & threads)111 void PerfEventsTest::RunTestThreads(std::vector<std::thread> &threads)
112 {
113 long processorNum = GetProcessorNum();
114 for (long i = 0; i < processorNum; i++) {
115 threads.emplace_back(std::thread(&TestCodeThread));
116 }
117 }
118
119 // it isn't include sample and stat
SetAllConfig(PerfEvents & event)120 void PerfEventsTest::SetAllConfig(PerfEvents &event)
121 {
122 std::vector<pid_t> selectCpus_;
123 event.SetCpu(selectCpus_);
124 std::vector<pid_t> pids;
125 event.SetPid(pids);
126 event.SetSystemTarget(true);
127 event.SetTimeOut(DEFAULT_TRACKING_TIME);
128 event.SetInherit(false);
129 std::vector<std::string> trackedCommand_ {};
130 event.SetTrackedCommand(trackedCommand_);
131 const unsigned int frequency = 4000;
132 event.SetSampleFrequency(frequency);
133 const uint32_t dwarfSampleStackSize = 64;
134 event.SetDwarfSampleStackSize(dwarfSampleStackSize);
135 const int clockId = 1;
136 event.SetClockId(clockId);
137
138 // addevent must be tail
139 event.AddDefaultEvent(PERF_TYPE_HARDWARE);
140 event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
141 }
142
RunTrack(PerfEvents & event)143 static void RunTrack(PerfEvents &event)
144 {
145 ASSERT_EQ(event.StartTracking(), true);
146 }
147
148 /**
149 * @tc.name: Test
150 * @tc.desc:
151 * @tc.type: FUNC
152 */
153 HWTEST_F(PerfEventsTest, GetSupportEvents, TestSize.Level1)
154 {
155 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
156 StdoutRecord stdoutRecord;
157 stdoutRecord.Start();
158
159 PerfEvents event;
160 perf_type_id id = PERF_TYPE_HARDWARE;
161 while (id < PERF_TYPE_MAX) {
162 std::map<__u64, std::string> supportEvent = event.GetSupportEvents(id);
163 for (auto it = supportEvent.begin(); it != supportEvent.end(); ++it) {
164 printf("[%lld]\t%s\n", it->first, it->second.c_str());
165 }
166 id = perf_type_id(id + 1);
167 }
168
169 std::string stringOut = stdoutRecord.Stop();
170 }
171
172 HWTEST_F(PerfEventsTest, GetTypeName, TestSize.Level1)
173 {
174 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
175 StdoutRecord stdoutRecord;
176 stdoutRecord.Start();
177
178 PerfEvents event;
179 perf_type_id id = PERF_TYPE_HARDWARE;
180 while (id < PERF_TYPE_MAX) {
181 std::string typeName = event.GetTypeName(id);
182 EXPECT_GT(typeName.size(), 0u) << "the type should have name";
183 printf("type[%d]\tname : %s\n", id, typeName.c_str());
184 id = perf_type_id(id + 1);
185 }
186
187 std::string stringOut = stdoutRecord.Stop();
188 }
189
190 HWTEST_F(PerfEventsTest, RecordNormal, TestSize.Level1)
191 {
192 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
193 StdoutRecord stdoutRecord;
194 stdoutRecord.Start();
195
196 PerfEvents event;
197 // prepare
198 g_recordCount = 0;
199 event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
200 event.SetRecordCallBack(RecordCount);
201
202 std::vector<pid_t> selectCpus_;
203 event.SetCpu(selectCpus_);
204 std::vector<pid_t> pids;
205 event.SetPid(pids);
206 event.SetSystemTarget(true);
207 event.SetTimeOut(DEFAULT_TRACKING_TIME);
208 event.SetInherit(false);
209 std::vector<std::string> trackedCommand_ {};
210 event.SetTrackedCommand(trackedCommand_);
211 event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
212 event.AddDefaultEvent(PERF_TYPE_HARDWARE);
213
214 ASSERT_EQ(event.PrepareTracking(), true);
215 std::thread runThread(RunTrack, std::ref(event));
216 std::vector<std::thread> testThreads;
217 RunTestThreads(testThreads);
218
219 std::this_thread::sleep_for(TEST_TIME);
220 EXPECT_EQ(event.PauseTracking(), true);
221 std::this_thread::sleep_for(TEST_TIME); // wait for clearing mmap buffer
222 uint64_t recordCount = g_recordCount;
223 std::this_thread::sleep_for(TEST_TIME);
224 EXPECT_EQ(recordCount, g_recordCount) << "now should have no record";
225 EXPECT_EQ(event.ResumeTracking(), true);
226 TestCodeThread();
227 std::this_thread::sleep_for(TEST_TIME);
228 EXPECT_EQ(event.StopTracking(), true);
229 runThread.join();
230 for (std::thread &t : testThreads) {
231 t.join();
232 }
233 ASSERT_GT(g_recordCount, recordCount) << "should have more records";
234
235 size_t lostSamples = 0;
236 size_t lostNonSamples = 0;
237 event.GetLostSamples(lostSamples, lostNonSamples);
238
239 std::string stringOut = stdoutRecord.Stop();
240 }
241
242 HWTEST_F(PerfEventsTest, RecordSetAll, TestSize.Level1)
243 {
244 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
245 StdoutRecord stdoutRecord;
246 stdoutRecord.Start();
247
248 PerfEvents event;
249 // prepare
250 g_recordCount = 0;
251 event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
252 event.SetRecordCallBack(RecordCount);
253 SetAllConfig(event);
254 ASSERT_EQ(event.PrepareTracking(), true);
255 std::thread runThread(RunTrack, std::ref(event));
256 std::vector<std::thread> testThreads;
257 RunTestThreads(testThreads);
258
259 std::this_thread::sleep_for(TEST_TIME);
260 EXPECT_EQ(event.PauseTracking(), true);
261 std::this_thread::sleep_for(TEST_TIME); // wait for clearing mmap buffer
262 uint64_t recordCount = g_recordCount;
263 std::this_thread::sleep_for(TEST_TIME);
264 EXPECT_EQ(recordCount, g_recordCount) << "now should have no record";
265 EXPECT_EQ(event.ResumeTracking(), true);
266 TestCodeThread();
267 std::this_thread::sleep_for(TEST_TIME);
268 EXPECT_EQ(event.StopTracking(), true);
269 runThread.join();
270 for (std::thread &t : testThreads) {
271 t.join();
272 }
273 ASSERT_GT(g_recordCount, recordCount) << "should have more records";
274
275 std::string stringOut = stdoutRecord.Stop();
276 }
277
278 HWTEST_F(PerfEventsTest, StatNormal, TestSize.Level1)
279 {
280 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
281 StdoutRecord stdoutRecord;
282 stdoutRecord.Start();
283
284 PerfEvents event;
285 // prepare
286 g_statCount = 0;
287 std::vector<pid_t> selectCpus_;
288 event.SetCpu(selectCpus_);
289 std::vector<pid_t> pids;
290 event.SetPid(pids);
291 event.SetSystemTarget(true);
292 event.SetTimeOut(DEFAULT_TRACKING_TIME);
293 event.SetTimeReport(DEFAULT_STAT_REPORT_TIME);
294 event.SetVerboseReport(false);
295 event.SetInherit(false);
296 std::vector<std::string> trackedCommand_;
297 event.SetTrackedCommand(trackedCommand_);
298 event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
299 event.AddDefaultEvent(PERF_TYPE_TRACEPOINT);
300 event.SetStatCallBack(StatCount);
301 ASSERT_EQ(event.PrepareTracking(), true);
302 std::thread runThread(RunTrack, std::ref(event));
303 std::vector<std::thread> testThreads;
304 RunTestThreads(testThreads);
305
306 std::this_thread::sleep_for(TEST_TIME);
307 EXPECT_EQ(event.PauseTracking(), true);
308 EXPECT_GT(g_statCount, 0u) << "should have stats";
309 uint64_t statCount = g_statCount;
310 std::this_thread::sleep_for(TEST_TIME);
311 EXPECT_EQ(event.ResumeTracking(), true);
312 std::this_thread::sleep_for(TEST_TIME);
313 EXPECT_EQ(event.StopTracking(), true);
314 runThread.join();
315 for (std::thread &t : testThreads) {
316 t.join();
317 }
318 EXPECT_GT(g_statCount, statCount) << "should have more stats";
319
320 std::string stringOut = stdoutRecord.Stop();
321 }
322 } // namespace HiPerf
323 } // namespace Developtools
324 } // namespace OHOS
325