• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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