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