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
30 namespace OHOS {
31 namespace Developtools {
32 namespace HiPerf {
33 static constexpr uint64_t NANO_SECONDS_PER_SECOND = 1000000000;
34 static constexpr uint64_t TEN_THOUSAND = 10000u;
35 static constexpr uint64_t PAGE_SIZE = 1024u;
36 static constexpr uint64_t SEVENTEEN = 17u;
37
38 class PerfEventsTest : public testing::Test {
39 public:
40 static void SetUpTestCase(void);
41 static void TearDownTestCase(void);
42 void SetUp();
43 void TearDown();
44
45 static void TestCodeThread(void);
46 static void RunTestThreads(std::vector<std::thread> &threads);
47 static void SetAllConfig(PerfEvents &event);
48 static bool RecordCount(PerfEventRecord& record);
49 static void StatCount(
50 const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &countEvents, FILE* filePtr);
51
52 static constexpr int TEST_CODE_MEM_FILE_SIZE = 1024;
53 static constexpr auto TEST_CODE_SLEEP_BEFORE_RUN = 500ms;
54 static constexpr auto TEST_CODE_SLEEP_AFTER_RUN = 1000ms;
55 static constexpr int TEST_CODE_RUN_TIME = 10240;
56 static constexpr int DOUBLE = 2;
57 static constexpr int TRIPLE = 3;
58 static constexpr auto TEST_TIME = 3s;
59 static constexpr auto DEFAULT_TRACKING_TIME = 1000;
60 static constexpr auto DEFAULT_STAT_REPORT_TIME = 500;
61 static constexpr auto DEFAULT_SAMPLE_MMAPAGE = 256;
62
63 static uint64_t gRecordCount;
64 static uint64_t gStatCount;
65 };
66
SetUpTestCase()67 void PerfEventsTest::SetUpTestCase() {}
68
TearDownTestCase()69 void PerfEventsTest::TearDownTestCase() {}
70
SetUp()71 void PerfEventsTest::SetUp() {}
72
TearDown()73 void PerfEventsTest::TearDown() {}
74
75 uint64_t PerfEventsTest::gRecordCount = 0;
76 uint64_t PerfEventsTest::gStatCount = 0;
77
RecordCount(PerfEventRecord & record)78 bool PerfEventsTest::RecordCount(PerfEventRecord& record)
79 {
80 gRecordCount++;
81 return true;
82 }
83
StatCount(const std::map<std::string,std::unique_ptr<PerfEvents::CountEvent>> & countEvents,FILE * filePtr)84 void PerfEventsTest::StatCount(
85 const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &countEvents, FILE* filePtr)
86 {
87 gStatCount++;
88 }
89
TestCodeThread()90 void PerfEventsTest::TestCodeThread()
91 {
92 std::vector<std::unique_ptr<char[]>> mems;
93 int tid = gettid();
94 printf("%s:%d ++\n", __FUNCTION__, tid);
95 for (int n = 0; n < TRIPLE; n++) {
96 std::this_thread::sleep_for(TEST_CODE_SLEEP_BEFORE_RUN);
97 constexpr size_t memSize {TEST_CODE_MEM_FILE_SIZE};
98 for (int i = 0; i < TEST_CODE_RUN_TIME; i++) {
99 if (i % DOUBLE == 0) {
100 mems.push_back(std::make_unique<char[]>(memSize));
101 } else {
102 mems.push_back(std::make_unique<char[]>(memSize * DOUBLE));
103 }
104 }
105
106 for (int i = 0; i < TEST_CODE_RUN_TIME; i++) {
107 mems.pop_back();
108 }
109
110 std::this_thread::sleep_for(TEST_CODE_SLEEP_AFTER_RUN);
111 }
112 printf("%s:%d --\n", __FUNCTION__, tid);
113 }
114
RunTestThreads(std::vector<std::thread> & threads)115 void PerfEventsTest::RunTestThreads(std::vector<std::thread> &threads)
116 {
117 for (long i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) {
118 threads.emplace_back(std::thread(&TestCodeThread));
119 }
120 }
121
122 // it isn't include sample and stat
SetAllConfig(PerfEvents & event)123 void PerfEventsTest::SetAllConfig(PerfEvents &event)
124 {
125 std::vector<pid_t> selectCpus_;
126 event.SetCpu(selectCpus_);
127 std::vector<pid_t> pids;
128 event.SetPid(pids);
129 event.SetSystemTarget(true);
130 event.SetTimeOut(DEFAULT_TRACKING_TIME);
131 event.SetInherit(false);
132 std::vector<std::string> trackedCommand_ {"ls"};
133 event.SetTrackedCommand(trackedCommand_);
134 const unsigned int frequency = 1000;
135 event.SetSampleFrequency(frequency);
136 const uint32_t dwarfSampleStackSize = 64;
137 event.SetDwarfSampleStackSize(dwarfSampleStackSize);
138 const int clockId = 1;
139 event.SetClockId(clockId);
140
141 // addevent must be tail
142 event.AddDefaultEvent(PERF_TYPE_HARDWARE);
143 event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
144 }
145
RunTrack(PerfEvents & event)146 static void RunTrack(PerfEvents &event)
147 {
148 ASSERT_EQ(event.StartTracking(), true);
149 }
150
151 /**
152 * @tc.name: Test
153 * @tc.desc:
154 * @tc.type: FUNC
155 */
156 HWTEST_F(PerfEventsTest, GetSupportEvents, TestSize.Level1)
157 {
158 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
159 StdoutRecord stdoutRecord;
160 stdoutRecord.Start();
161
162 PerfEvents event;
163 perf_type_id id = PERF_TYPE_HARDWARE;
164 int index = 0;
165 bool value[] = {false, false, false, false, false, true};
166 while (id < PERF_TYPE_MAX) {
167 std::map<__u64, std::string> supportEvent = event.GetSupportEvents(id);
168 ASSERT_EQ(supportEvent.empty(), value[index++]);
169 for (auto it = supportEvent.begin(); it != supportEvent.end(); ++it) {
170 printf("[%lld]\t%s\n", it->first, it->second.c_str());
171 }
172 id = perf_type_id(id + 1);
173 }
174
175 std::string stringOut = stdoutRecord.Stop();
176 }
177
178 HWTEST_F(PerfEventsTest, GetTypeName, TestSize.Level2)
179 {
180 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
181 StdoutRecord stdoutRecord;
182 stdoutRecord.Start();
183
184 PerfEvents event;
185 perf_type_id id = PERF_TYPE_HARDWARE;
186 while (id < PERF_TYPE_MAX) {
187 std::string typeName = event.GetTypeName(id);
188 EXPECT_GT(typeName.size(), 0u) << "the type should have name";
189 printf("type[%d]\tname : %s\n", id, typeName.c_str());
190 id = perf_type_id(id + 1);
191 }
192
193 std::string stringOut = stdoutRecord.Stop();
194 }
195
196 HWTEST_F(PerfEventsTest, RecordNormal, TestSize.Level1)
197 {
198 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
199 StdoutRecord stdoutRecord;
200 stdoutRecord.Start();
201
202 PerfEvents event;
203 // prepare
204 gRecordCount = 0;
205 event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
206 event.SetRecordCallBack(RecordCount);
207
208 std::vector<pid_t> selectCpus_;
209 event.SetCpu(selectCpus_);
210 std::vector<pid_t> pids;
211 event.SetPid(pids);
212 const unsigned int frequency = 1000;
213 event.SetSampleFrequency(frequency);
214 event.SetSystemTarget(true);
215 event.SetTimeOut(DEFAULT_TRACKING_TIME);
216 event.SetInherit(false);
217 std::vector<std::string> trackedCommand_ {"ls"};
218 event.SetTrackedCommand(trackedCommand_);
219 event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
220 event.AddDefaultEvent(PERF_TYPE_HARDWARE);
221
222 ASSERT_EQ(event.PrepareTracking(), true);
223 std::thread runThread(RunTrack, std::ref(event));
224 std::vector<std::thread> testThreads;
225 RunTestThreads(testThreads);
226
227 std::this_thread::sleep_for(TEST_TIME);
228 EXPECT_EQ(event.PauseTracking(), true);
229 std::this_thread::sleep_for(TEST_TIME); // wait for clearing mmap buffer
230 uint64_t recordCount = gRecordCount;
231 std::this_thread::sleep_for(TEST_TIME);
232 EXPECT_EQ(recordCount, gRecordCount) << "now should have no record";
233 EXPECT_EQ(event.ResumeTracking(), true);
234 TestCodeThread();
235 std::this_thread::sleep_for(TEST_TIME);
236 EXPECT_EQ(event.StopTracking(), true);
237 runThread.join();
238 for (std::thread &t : testThreads) {
239 t.join();
240 }
241 ASSERT_GT(gRecordCount, recordCount) << "should have more records";
242
243 size_t lostSamples = 0;
244 size_t lostNonSamples = 0;
245 event.GetLostSamples(lostSamples, lostNonSamples);
246
247 std::string stringOut = stdoutRecord.Stop();
248 }
249
250 HWTEST_F(PerfEventsTest, RecordSetAll, TestSize.Level0)
251 {
252 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
253 StdoutRecord stdoutRecord;
254 stdoutRecord.Start();
255
256 PerfEvents event;
257 // prepare
258 gRecordCount = 0;
259 event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
260 event.SetRecordCallBack(RecordCount);
261 SetAllConfig(event);
262 ASSERT_EQ(event.PrepareTracking(), true);
263 std::thread runThread(RunTrack, std::ref(event));
264 std::vector<std::thread> testThreads;
265 RunTestThreads(testThreads);
266
267 std::this_thread::sleep_for(TEST_TIME);
268 EXPECT_EQ(event.PauseTracking(), true);
269 std::this_thread::sleep_for(TEST_TIME); // wait for clearing mmap buffer
270 uint64_t recordCount = gRecordCount;
271 std::this_thread::sleep_for(TEST_TIME);
272 EXPECT_EQ(recordCount, gRecordCount) << "now should have no record";
273 EXPECT_EQ(event.ResumeTracking(), true);
274 TestCodeThread();
275 std::this_thread::sleep_for(TEST_TIME);
276 EXPECT_EQ(event.StopTracking(), true);
277 runThread.join();
278 for (std::thread &t : testThreads) {
279 t.join();
280 }
281 ASSERT_GT(gRecordCount, recordCount) << "should have more records";
282
283 std::string stringOut = stdoutRecord.Stop();
284 }
285
286 HWTEST_F(PerfEventsTest, StatNormal, TestSize.Level0)
287 {
288 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
289 StdoutRecord stdoutRecord;
290 stdoutRecord.Start();
291
292 PerfEvents event;
293 FILE* filePtr = nullptr;
294 // prepare
295 gStatCount = 0;
296 std::vector<pid_t> selectCpus_;
297 event.SetCpu(selectCpus_);
298 std::vector<pid_t> pids;
299 event.SetPid(pids);
300 event.SetSystemTarget(true);
301 event.SetTimeOut(DEFAULT_TRACKING_TIME);
302 event.SetTimeReport(DEFAULT_STAT_REPORT_TIME);
303 event.SetVerboseReport(false);
304 event.SetInherit(false);
305 std::vector<std::string> trackedCommand_ {"ls"};
306 event.SetTrackedCommand(trackedCommand_);
307 event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
308 event.AddDefaultEvent(PERF_TYPE_TRACEPOINT);
309 event.SetStatCallBack(StatCount);
310 event.SetStatReportFd(filePtr);
311 ASSERT_EQ(event.PrepareTracking(), true);
312 std::thread runThread(RunTrack, std::ref(event));
313 std::vector<std::thread> testThreads;
314 RunTestThreads(testThreads);
315
316 std::this_thread::sleep_for(TEST_TIME);
317 EXPECT_EQ(event.PauseTracking(), true);
318 EXPECT_GT(gStatCount, 0u) << "should have stats";
319 uint64_t statCount = gStatCount;
320 std::this_thread::sleep_for(TEST_TIME);
321 EXPECT_EQ(event.ResumeTracking(), true);
322 std::this_thread::sleep_for(TEST_TIME);
323 EXPECT_EQ(event.StopTracking(), true);
324 runThread.join();
325 for (std::thread &t : testThreads) {
326 t.join();
327 }
328 EXPECT_GT(gStatCount, statCount) << "should have more stats";
329
330 std::string stringOut = stdoutRecord.Stop();
331 }
332
333 HWTEST_F(PerfEventsTest, CreateUpdateTimeThread2, TestSize.Level0)
334 {
335 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
336 StdoutRecord stdoutRecord;
337 stdoutRecord.Start();
338
339 PerfEvents event;
340 event.backtrack_ = true;
341 event.eventGroupItem_.emplace_back();
342 event.eventGroupItem_[0].eventItems.emplace_back();
343 event.readRecordThreadRunning_ = true;
344 EXPECT_EQ(event.PrepareRecordThread(), true);
345 this_thread::sleep_for(1s);
346 std::vector<pid_t> tids = GetSubthreadIDs(getpid());
347 EXPECT_FALSE(tids.empty());
348 bool get = false;
349 for (const pid_t tid : tids) {
350 std::string threadName = ReadFileToString(StringPrintf("/proc/%d/comm", tid));
351 while (threadName.back() == '\0' || threadName.back() == '\n') {
352 threadName.pop_back();
353 }
354 if (threadName == "timer_thread") {
355 get = true;
356 break;
357 }
358 }
359 EXPECT_EQ(get, true);
360 PerfEvents::updateTimeThreadRunning_ = false;
361 this_thread::sleep_for(1s);
362 }
363
364 HWTEST_F(PerfEventsTest, IsOutputTracking, TestSize.Level2)
365 {
366 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
367 StdoutRecord stdoutRecord;
368 stdoutRecord.Start();
369
370 PerfEvents event;
371 EXPECT_EQ(event.IsOutputTracking(), false);
372 event.outputTracking_ = true;
373 EXPECT_EQ(event.IsOutputTracking(), true);
374 }
375
376 HWTEST_F(PerfEventsTest, SetBackTrack, TestSize.Level1)
377 {
378 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
379 StdoutRecord stdoutRecord;
380 stdoutRecord.Start();
381
382 PerfEvents event;
383 event.SetBackTrack(true);
384 EXPECT_EQ(event.backtrack_, true);
385 }
386
387 HWTEST_F(PerfEventsTest, CalcBufferSizeLittleMemory, TestSize.Level2)
388 {
389 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
390 StdoutRecord stdoutRecord;
391 stdoutRecord.Start();
392
393 if (LittleMemory()) {
394 PerfEvents event;
395 event.backtrack_ = false;
396 event.systemTarget_ = true;
397 EXPECT_EQ(event.CalcBufferSize(), PerfEvents::MAX_BUFFER_SIZE_LITTLE);
398
399 event.backtrack_ = true;
400 event.cpuMmap_.clear();
401 EXPECT_EQ(event.CalcBufferSize(), PerfEvents::MIN_BUFFER_SIZE);
402
403 event.cpuMmap_[0] = {};
404 event.mmapPages_ = TEN_THOUSAND;
405 event.pageSize_ = TEN_THOUSAND;
406 EXPECT_EQ(event.CalcBufferSize(), PerfEvents::MAX_BUFFER_SIZE_LITTLE);
407
408 while (event.cpuMmap_.size() < SEVENTEEN) {
409 event.cpuMmap_[event.cpuMmap_.size()] = {};
410 }
411 event.mmapPages_ = PAGE_SIZE;
412 event.pageSize_ = PAGE_SIZE;
413 static constexpr size_t EXPECT_SIZE = SEVENTEEN * PAGE_SIZE * PAGE_SIZE * 4;
414 EXPECT_EQ(event.CalcBufferSize(), EXPECT_SIZE);
415 }
416 }
417
418 HWTEST_F(PerfEventsTest, CalcBufferSizeLargeMemory, TestSize.Level1)
419 {
420 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
421 StdoutRecord stdoutRecord;
422 stdoutRecord.Start();
423
424 if (!LittleMemory()) {
425 PerfEvents event;
426 size_t maxBufferSize = PerfEvents::MAX_BUFFER_SIZE_LARGE;
427 size_t minBufferSize = PerfEvents::MIN_BUFFER_SIZE;
428 event.GetBufferSizeCfg(maxBufferSize, minBufferSize);
429
430 event.backtrack_ = false;
431 event.systemTarget_ = true;
432 EXPECT_EQ(event.CalcBufferSize(), maxBufferSize);
433
434 event.backtrack_ = true;
435 event.cpuMmap_.clear();
436 EXPECT_EQ(event.CalcBufferSize(), minBufferSize);
437
438 event.cpuMmap_[0] = {};
439 event.mmapPages_ = TEN_THOUSAND;
440 event.pageSize_ = TEN_THOUSAND;
441 EXPECT_EQ(event.CalcBufferSize(), maxBufferSize);
442
443 while (event.cpuMmap_.size() < SEVENTEEN) {
444 event.cpuMmap_[event.cpuMmap_.size()] = {};
445 }
446 event.mmapPages_ = PAGE_SIZE;
447 event.pageSize_ = PAGE_SIZE;
448 static constexpr size_t EXPECT_SIZE = SEVENTEEN * PAGE_SIZE * PAGE_SIZE * 4;
449 if (!CheckOutOfRange(EXPECT_SIZE, minBufferSize, maxBufferSize)) {
450 EXPECT_EQ(event.CalcBufferSize(), EXPECT_SIZE);
451 }
452 }
453 }
454
455 HWTEST_F(PerfEventsTest, IsSkipRecordForBacktrack1, TestSize.Level1)
456 {
457 static constexpr size_t BACKTRACK_TIME = 2000u;
458 static constexpr size_t SAMPLE_TIME = 1234u;
459 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
460 StdoutRecord stdoutRecord;
461 stdoutRecord.Start();
462
463 PerfEvents event;
464 event.outputTracking_ = false;
465 event.backtrackTime_ = BACKTRACK_TIME * NANO_SECONDS_PER_SECOND;
466 event.currentTimeSecond_.store(event.backtrackTime_);
467
468 PerfRecordSample sample;
469 sample.data_.time = SAMPLE_TIME * NANO_SECONDS_PER_SECOND;
470
471 EXPECT_EQ(event.IsSkipRecordForBacktrack(sample), true);
472 }
473
474 HWTEST_F(PerfEventsTest, IsSkipRecordForBacktrack2, TestSize.Level2)
475 {
476 static constexpr size_t END_TIME = 2000u;
477 static constexpr size_t SAMPLE_TIME = 1234u;
478 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
479 StdoutRecord stdoutRecord;
480 stdoutRecord.Start();
481
482 PerfEvents event;
483 event.outputTracking_ = true;
484 event.outputEndTime_ = END_TIME * NANO_SECONDS_PER_SECOND;
485
486 PerfRecordSample sample;
487 sample.data_.time = SAMPLE_TIME * NANO_SECONDS_PER_SECOND;
488
489 EXPECT_EQ(event.IsSkipRecordForBacktrack(sample), false);
490 }
491
492 HWTEST_F(PerfEventsTest, IsSkipRecordForBacktrack3, TestSize.Level2)
493 {
494 static constexpr size_t END_TIME = 1000u;
495 static constexpr size_t SAMPLE_TIME = 1234u;
496 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
497 StdoutRecord stdoutRecord;
498 stdoutRecord.Start();
499
500 PerfEvents event;
501 event.outputTracking_ = true;
502 event.outputEndTime_ = END_TIME;
503
504 PerfRecordSample sample;
505 sample.data_.time = SAMPLE_TIME * NANO_SECONDS_PER_SECOND;
506
507 EXPECT_EQ(event.IsSkipRecordForBacktrack(sample), true);
508 EXPECT_EQ(event.outputTracking_, false);
509 EXPECT_EQ(event.outputEndTime_, 0);
510 }
511
512 HWTEST_F(PerfEventsTest, OutputTracking, TestSize.Level1)
513 {
514 static constexpr size_t TIME = 1234u;
515 ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
516 StdoutRecord stdoutRecord;
517 stdoutRecord.Start();
518
519 PerfEvents event;
520 event.startedTracking_ = false;
521 EXPECT_EQ(event.OutputTracking(), false);
522
523 event.startedTracking_ = true;
524 event.outputTracking_ = true;
525 EXPECT_EQ(event.OutputTracking(), true);
526
527 event.outputTracking_ = false;
528 PerfEvents::currentTimeSecond_.store(TIME);
529 EXPECT_EQ(event.OutputTracking(), true);
530 EXPECT_EQ(event.outputEndTime_, TIME);
531 EXPECT_EQ(event.outputTracking_, true);
532 }
533
534 HWTEST_F(PerfEventsTest, SetConfig, TestSize.Level1)
535 {
536 constexpr uint64_t config = 0x700010007;
537 constexpr uint64_t config1 = 8;
538 constexpr uint64_t config2 = 10;
539 PerfEvents event;
540 std::map<const std::string, uint64_t> speOptMap = {
541 {"branch_filter", 1}, {"load_filter", 1},
542 {"store_filter", 1}, {"ts_enable", 1},
543 {"pa_enable", 1}, {"jitter", 1},
544 {"min_latency", config2}, {"event_filter", config1},
545 {"pct_enable", 1},
546 };
547 event.SetConfig(speOptMap);
548 EXPECT_EQ(event.config_, config);
549 EXPECT_EQ(event.config1_, config1);
550 EXPECT_EQ(event.config2_, config2);
551 }
552
553 HWTEST_F(PerfEventsTest, SetConfig1, TestSize.Level2)
554 {
555 constexpr uint64_t config = 0x700010003;
556 PerfEvents event;
557 std::map<const std::string, uint64_t> speOptMap = {
558 {"branch_filter", 1}, {"load_filter", 1},
559 {"store_filter", 1}, {"ts_enable", 1},
560 {"pa_enable", 1}, {"jitter", 1},
561 {"min_latency", 0}, {"event_filter", 0},
562 {"pct_enable", 0},
563 };
564 event.SetConfig(speOptMap);
565 EXPECT_EQ(event.config_, config);
566 }
567 } // namespace HiPerf
568 } // namespace Developtools
569 } // namespace OHOS
570