• 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 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     if (record->GetType() == PERF_RECORD_SAMPLE) {
78         if (record->GetType() == PERF_RECORD_SAMPLE) {
79             // the record is allowed from a cache memory, does not free memory after use
80             record.release();
81         }
82     }
83     return true;
84 }
85 
StatCount(const std::map<std::string,std::unique_ptr<PerfEvents::CountEvent>> & countEvents)86 void PerfEventsTest::StatCount(
87     const std::map<std::string, std::unique_ptr<PerfEvents::CountEvent>> &countEvents)
88 {
89     g_statCount++;
90 }
91 
TestCodeThread()92 void PerfEventsTest::TestCodeThread()
93 {
94     std::vector<std::unique_ptr<char[]>> mems;
95     int tid = gettid();
96     printf("%s:%d ++\n", __FUNCTION__, tid);
97     for (int n = 0; n < TRIPLE; n++) {
98         std::this_thread::sleep_for(TEST_CODE_SLEEP_BEFORE_RUN);
99         constexpr size_t memSize {TEST_CODE_MEM_FILE_SIZE};
100         for (int i = 0; i < TEST_CODE_RUN_TIME; i++) {
101             if (i % DOUBLE == 0) {
102                 mems.push_back(std::make_unique<char[]>(memSize));
103             } else {
104                 mems.push_back(std::make_unique<char[]>(memSize * DOUBLE));
105             }
106         }
107 
108         for (int i = 0; i < TEST_CODE_RUN_TIME; i++) {
109             mems.pop_back();
110         }
111 
112         std::this_thread::sleep_for(TEST_CODE_SLEEP_AFTER_RUN);
113     }
114     printf("%s:%d --\n", __FUNCTION__, tid);
115 }
116 
RunTestThreads(std::vector<std::thread> & threads)117 void PerfEventsTest::RunTestThreads(std::vector<std::thread> &threads)
118 {
119     for (long i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) {
120         threads.emplace_back(std::thread(&TestCodeThread));
121     }
122 }
123 
124 // it isn't include sample and stat
SetAllConfig(PerfEvents & event)125 void PerfEventsTest::SetAllConfig(PerfEvents &event)
126 {
127     std::vector<pid_t> selectCpus_;
128     event.SetCpu(selectCpus_);
129     std::vector<pid_t> pids;
130     event.SetPid(pids);
131     event.SetSystemTarget(true);
132     event.SetTimeOut(DEFAULT_TRACKING_TIME);
133     event.SetInherit(false);
134     std::vector<std::string> trackedCommand_ {};
135     event.SetTrackedCommand(trackedCommand_);
136     const unsigned int frequency = 1000;
137     event.SetSampleFrequency(frequency);
138     const uint32_t dwarfSampleStackSize = 64;
139     event.SetDwarfSampleStackSize(dwarfSampleStackSize);
140     const int clockId = 1;
141     event.SetClockId(clockId);
142 
143     // addevent must be tail
144     event.AddDefaultEvent(PERF_TYPE_HARDWARE);
145     event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
146 }
147 
RunTrack(PerfEvents & event)148 static void RunTrack(PerfEvents &event)
149 {
150     ASSERT_EQ(event.StartTracking(), true);
151 }
152 
153 /**
154  * @tc.name: Test
155  * @tc.desc:
156  * @tc.type: FUNC
157  */
158 HWTEST_F(PerfEventsTest, GetSupportEvents, TestSize.Level1)
159 {
160     ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
161     StdoutRecord stdoutRecord;
162     stdoutRecord.Start();
163 
164     PerfEvents event;
165     perf_type_id id = PERF_TYPE_HARDWARE;
166     while (id < PERF_TYPE_MAX) {
167         std::map<__u64, std::string> supportEvent = event.GetSupportEvents(id);
168         for (auto it = supportEvent.begin(); it != supportEvent.end(); ++it) {
169             printf("[%lld]\t%s\n", it->first, it->second.c_str());
170         }
171         id = perf_type_id(id + 1);
172     }
173 
174     std::string stringOut = stdoutRecord.Stop();
175 }
176 
177 HWTEST_F(PerfEventsTest, GetTypeName, TestSize.Level1)
178 {
179     ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
180     StdoutRecord stdoutRecord;
181     stdoutRecord.Start();
182 
183     PerfEvents event;
184     perf_type_id id = PERF_TYPE_HARDWARE;
185     while (id < PERF_TYPE_MAX) {
186         std::string typeName = event.GetTypeName(id);
187         EXPECT_GT(typeName.size(), 0u) << "the type should have name";
188         printf("type[%d]\tname : %s\n", id, typeName.c_str());
189         id = perf_type_id(id + 1);
190     }
191 
192     std::string stringOut = stdoutRecord.Stop();
193 }
194 
195 HWTEST_F(PerfEventsTest, RecordNormal, TestSize.Level1)
196 {
197     ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
198     StdoutRecord stdoutRecord;
199     stdoutRecord.Start();
200 
201     PerfEvents event;
202     // prepare
203     g_recordCount = 0;
204     event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
205     event.SetRecordCallBack(RecordCount);
206 
207     std::vector<pid_t> selectCpus_;
208     event.SetCpu(selectCpus_);
209     std::vector<pid_t> pids;
210     event.SetPid(pids);
211     const unsigned int frequency = 1000;
212     event.SetSampleFrequency(frequency);
213     event.SetSystemTarget(true);
214     event.SetTimeOut(DEFAULT_TRACKING_TIME);
215     event.SetInherit(false);
216     std::vector<std::string> trackedCommand_ {};
217     event.SetTrackedCommand(trackedCommand_);
218     event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
219     event.AddDefaultEvent(PERF_TYPE_HARDWARE);
220 
221     ASSERT_EQ(event.PrepareTracking(), true);
222     std::thread runThread(RunTrack, std::ref(event));
223     std::vector<std::thread> testThreads;
224     RunTestThreads(testThreads);
225 
226     std::this_thread::sleep_for(TEST_TIME);
227     EXPECT_EQ(event.PauseTracking(), true);
228     std::this_thread::sleep_for(TEST_TIME); // wait for clearing mmap buffer
229     uint64_t recordCount = g_recordCount;
230     std::this_thread::sleep_for(TEST_TIME);
231     EXPECT_EQ(recordCount, g_recordCount) << "now should have no record";
232     EXPECT_EQ(event.ResumeTracking(), true);
233     TestCodeThread();
234     std::this_thread::sleep_for(TEST_TIME);
235     EXPECT_EQ(event.StopTracking(), true);
236     runThread.join();
237     for (std::thread &t : testThreads) {
238         t.join();
239     }
240     ASSERT_GT(g_recordCount, recordCount) << "should have more records";
241 
242     size_t lostSamples = 0;
243     size_t lostNonSamples = 0;
244     event.GetLostSamples(lostSamples, lostNonSamples);
245 
246     std::string stringOut = stdoutRecord.Stop();
247 }
248 
249 HWTEST_F(PerfEventsTest, RecordSetAll, TestSize.Level1)
250 {
251     ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
252     StdoutRecord stdoutRecord;
253     stdoutRecord.Start();
254 
255     PerfEvents event;
256     // prepare
257     g_recordCount = 0;
258     event.SetMmapPages(DEFAULT_SAMPLE_MMAPAGE);
259     event.SetRecordCallBack(RecordCount);
260     SetAllConfig(event);
261     ASSERT_EQ(event.PrepareTracking(), true);
262     std::thread runThread(RunTrack, std::ref(event));
263     std::vector<std::thread> testThreads;
264     RunTestThreads(testThreads);
265 
266     std::this_thread::sleep_for(TEST_TIME);
267     EXPECT_EQ(event.PauseTracking(), true);
268     std::this_thread::sleep_for(TEST_TIME); // wait for clearing mmap buffer
269     uint64_t recordCount = g_recordCount;
270     std::this_thread::sleep_for(TEST_TIME);
271     EXPECT_EQ(recordCount, g_recordCount) << "now should have no record";
272     EXPECT_EQ(event.ResumeTracking(), true);
273     TestCodeThread();
274     std::this_thread::sleep_for(TEST_TIME);
275     EXPECT_EQ(event.StopTracking(), true);
276     runThread.join();
277     for (std::thread &t : testThreads) {
278         t.join();
279     }
280     ASSERT_GT(g_recordCount, recordCount) << "should have more records";
281 
282     std::string stringOut = stdoutRecord.Stop();
283 }
284 
285 HWTEST_F(PerfEventsTest, StatNormal, TestSize.Level1)
286 {
287     ScopeDebugLevel tempLogLevel(LEVEL_DEBUG);
288     StdoutRecord stdoutRecord;
289     stdoutRecord.Start();
290 
291     PerfEvents event;
292     // prepare
293     g_statCount = 0;
294     std::vector<pid_t> selectCpus_;
295     event.SetCpu(selectCpus_);
296     std::vector<pid_t> pids;
297     event.SetPid(pids);
298     event.SetSystemTarget(true);
299     event.SetTimeOut(DEFAULT_TRACKING_TIME);
300     event.SetTimeReport(DEFAULT_STAT_REPORT_TIME);
301     event.SetVerboseReport(false);
302     event.SetInherit(false);
303     std::vector<std::string> trackedCommand_;
304     event.SetTrackedCommand(trackedCommand_);
305     event.AddDefaultEvent(PERF_TYPE_SOFTWARE);
306     event.AddDefaultEvent(PERF_TYPE_TRACEPOINT);
307     event.SetStatCallBack(StatCount);
308     ASSERT_EQ(event.PrepareTracking(), true);
309     std::thread runThread(RunTrack, std::ref(event));
310     std::vector<std::thread> testThreads;
311     RunTestThreads(testThreads);
312 
313     std::this_thread::sleep_for(TEST_TIME);
314     EXPECT_EQ(event.PauseTracking(), true);
315     EXPECT_GT(g_statCount, 0u) << "should have stats";
316     uint64_t statCount = g_statCount;
317     std::this_thread::sleep_for(TEST_TIME);
318     EXPECT_EQ(event.ResumeTracking(), true);
319     std::this_thread::sleep_for(TEST_TIME);
320     EXPECT_EQ(event.StopTracking(), true);
321     runThread.join();
322     for (std::thread &t : testThreads) {
323         t.join();
324     }
325     EXPECT_GT(g_statCount, statCount) << "should have more stats";
326 
327     std::string stringOut = stdoutRecord.Stop();
328 }
329 } // namespace HiPerf
330 } // namespace Developtools
331 } // namespace OHOS
332