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 "cpu_usage_test.h"
17 #include "utilities_test.h"
18 using namespace std;
19 using namespace testing::ext;
20 using namespace std::chrono;
21 namespace OHOS {
22 namespace Developtools {
23 namespace Hiperf {
24 class CpuUsageTest : public testing::Test {
25 public:
26 static void SetUpTestCase(void);
27 static void TearDownTestCase(void);
28 void SetUp();
29 void TearDown();
30
31 pid_t GetPidByProcessName(std::string procName);
32
33 int GetVmRSSLine(pid_t pid);
34
35 const char* GetItems(const char* buffer, unsigned int item);
36
37 unsigned long GetCpuTotalUsage();
38
39 unsigned long GetCpuProcUsage(int pid);
40
41 float GetCpuUsageRatio(int pid);
42
43 float GetAverageCpuUsage(pid_t pid, uint64_t timeOut);
44
45 void TestCpuUsage(const std::string &option, unsigned int expect, bool fixPid);
46 };
47
SetUpTestCase()48 void CpuUsageTest::SetUpTestCase() {}
49
TearDownTestCase()50 void CpuUsageTest::TearDownTestCase() {}
51
SetUp()52 void CpuUsageTest::SetUp() {}
53
TearDown()54 void CpuUsageTest::TearDown() {}
55
GetPidByProcessName(std::string procName)56 pid_t CpuUsageTest::GetPidByProcessName(std::string procName)
57 {
58 FILE *fp = nullptr;
59 char buf[100];
60 pid_t pid = -1;
61 std::string cmd = "pidof " + procName;
62 if ((fp = popen(cmd.c_str(), "r")) != nullptr) {
63 if (fgets(buf, sizeof(buf), fp) != nullptr) {
64 pid = atoi(buf);
65 }
66 pclose(fp);
67 }
68 return pid;
69 }
70
GetVmRSSLine(pid_t pid)71 int CpuUsageTest::GetVmRSSLine(pid_t pid)
72 {
73 int line = 0;
74 std::string fileName = "/proc" + std::to_string(pid) + "/stat";
75 std::ifstream in(fileName, std::ios::in);
76 std::string tmp;
77 if (in.fail()) {
78 return 0;
79 } else {
80 while (getline(in, tmp)) {
81 line++;
82 if (tmp.find("VmRSS")) {
83 return line;
84 }
85 }
86 }
87 in.close();
88 return -1;
89 }
90
GetItems(const char * buffer,unsigned int item)91 const char* CpuUsageTest::GetItems(const char* buffer, unsigned int item)
92 {
93 // read from buffer by offset
94 const char* p = buffer;
95 int len = strlen(buffer);
96 int count = 0;
97 for (int i = 0; i < len; ++i) {
98 if (*p == ' ') {
99 count++;
100 if (count == item - 1) {
101 p++;
102 break;
103 }
104 }
105 p++;
106 }
107 return p;
108 }
109
GetCpuTotalUsage()110 unsigned long CpuUsageTest::GetCpuTotalUsage()
111 {
112 // get total cpu usage time from /proc/stat
113
114 // different mode cpu usage time
115 unsigned long userTime;
116 unsigned long niceTime;
117 unsigned long systemTime;
118 unsigned long idleTime;
119
120 FILE *fd = nullptr;
121 char buff[1024] = {0};
122 std::string fileName = "/proc/stat";
123 fd = fopen(fileName.c_str(), "r");
124 if (fd == nullptr) {
125 return 0;
126 }
127 fgets (buff, sizeof(buff), fd);
128 char name[64] = {0};
129 // get first line cpu time data
130 stringstream stream;
131 stream << buff;
132 stream >> name >> userTime >> niceTime >> systemTime >> idleTime;
133 fclose(fd);
134 stream.clear();
135 return (userTime + niceTime + systemTime + idleTime);
136 }
137
GetCpuProcUsage(int pid)138 unsigned long CpuUsageTest::GetCpuProcUsage(int pid)
139 {
140 // get cpu usage of specific pid
141
142 unsigned int tmpPid;
143 unsigned long utime; // user time
144 unsigned long stime; // kernel time
145 unsigned long cutime; // all usertime
146 unsigned long cstime; // all dead time
147
148 FILE *fd = nullptr;
149 char lineBuff[1024] = {0};
150 std::string fileName = "/proc" + std::to_string(pid) + "/stat";
151 fd = fopen(fileName.c_str(), "r");
152 if (fd == nullptr) {
153 return 0;
154 }
155 fgets(lineBuff, sizeof(lineBuff), fd);
156 stringstream stream;
157 stream << lineBuff;
158 stream >> tmpPid;
159 const char* q = GetItems(lineBuff, PROCESS_ITEM);
160 stream.clear();
161 stream << q;
162 stream >> utime >> stime >> cutime >> cstime;
163 fclose(fd);
164
165 return (utime + stime + cutime + cstime);
166 }
167
GetCpuUsageRatio(int pid)168 float CpuUsageTest::GetCpuUsageRatio(int pid)
169 {
170 unsigned long totalCpuTimepPrev;
171 unsigned long totalcputimeCur;
172 unsigned long procCpuTimepPrev;
173 unsigned long proccputimeCur;
174
175 totalCpuTimepPrev = GetCpuTotalUsage();
176 procCpuTimepPrev = GetCpuProcUsage(pid);
177
178 // sleep 200ms to get two point cpu usage snapshots
179 int timeInterval = 200000;
180 usleep(timeInterval);
181
182 totalcputimeCur = GetCpuTotalUsage();
183 proccputimeCur = GetCpuProcUsage(pid);
184
185 float pcpu = 0.0;
186 if (totalcputimeCur - totalCpuTimepPrev != 0) {
187 pcpu = (proccputimeCur - procCpuTimepPrev) / float(totalcputimeCur - totalCpuTimepPrev);
188 }
189
190 int cpuNum = get_nprocs();
191 // multi cpu machine should multiply cpu number
192 pcpu *= cpuNum;
193 return pcpu;
194 }
195
GetAverageCpuUsage(pid_t pid,uint64_t timeOut)196 float CpuUsageTest::GetAverageCpuUsage(pid_t pid, uint64_t timeOut)
197 {
198 float cpuUsage = 0.0;
199 int count = 0;
200 auto startTime = std::chrono::steady_clock::now();
201 while (true) {
202 ++count;
203 cpuUsage += GetCpuUsageRatio(pid);
204 auto thisTime = std::chrono::steady_clock::now();
205 if ((uint64_t)duration_cast<milliseconds>(thisTime - startTime).count()
206 > timeOut) {
207 break;
208 }
209 }
210 cpuUsage = HUNDRED * cpuUsage / count;
211 return cpuUsage;
212 }
213
TestCpuUsage(const std::string & option,unsigned int expect,bool fixPid)214 void CpuUsageTest::TestCpuUsage(const std::string &option, unsigned int expect, bool fixPid)
215 {
216 std::string cmd = "hiperf record ";
217 if (fixPid) {
218 cmd += "--app ";
219 cmd += " " + TEST_PROCESSES;
220 }
221 cmd += " " + option;
222
223 std::thread perf(system, cmd.c_str());
224 perf.detach();
225 pid_t pid = GetPidByProcessName("hiperf");
226 uint64_t timeOut = 10000;
227 float cpuUsage = GetAverageCpuUsage(pid, timeOut);
228
229 EXPECT_LE(cpuUsage, expect);
230 }
231
232 /**
233 * @tc.name: recordCpuUsageF100_FP_SYSTEM
234 * @tc.desc: test hiperf record system wide cpu usage within required limit
235 * @tc.type: FUNC
236 */
237 HWTEST_F(CpuUsageTest, recordCpuUsageF100_FP_SYSTEM, TestSize.Level1)
238 {
239 TestCpuUsage("-a -f 100 -s fp -d 10", F100_FP_CPU_LIMIT_SYSTEM, false);
240 }
241
242 /**
243 * @tc.name: recordCpuUsageF500_FP_SYSTEM
244 * @tc.desc: test hiperf record system wide cpu usage within required limit
245 * @tc.type: FUNC
246 */
247 HWTEST_F(CpuUsageTest, recordCpuUsageF500_FP_SYSTEM, TestSize.Level1)
248 {
249 TestCpuUsage("-a -f 500 -s fp -d 10", F500_FP_CPU_LIMIT_SYSTEM, false);
250 }
251
252 /**
253 * @tc.name: recordCpuUsageF1000_FP_SYSTEM
254 * @tc.desc: test hiperf record system wide cpu usage within required limit
255 * @tc.type: FUNC
256 */
257 HWTEST_F(CpuUsageTest, recordCpuUsageF1000_FP_SYSTEM, TestSize.Level1)
258 {
259 TestCpuUsage("-a -f 1000 -s fp -d 10", F1000_FP_CPU_LIMIT_SYSTEM, false);
260 }
261
262 /**
263 * @tc.name: recordCpuUsageF2000_FP_SYSTEM
264 * @tc.desc: test hiperf record system wide cpu usage within required limit
265 * @tc.type: FUNC
266 */
267 HWTEST_F(CpuUsageTest, recordCpuUsageF2000_FP_SYSTEM, TestSize.Level1)
268 {
269 TestCpuUsage("-a -f 2000 -s fp -d 10", F2000_FP_CPU_LIMIT_SYSTEM, false);
270 }
271
272 /**
273 * @tc.name: recordCpuUsageF4000_FP_SYSTEM
274 * @tc.desc: test hiperf record system wide cpu usage within required limit
275 * @tc.type: FUNC
276 */
277 HWTEST_F(CpuUsageTest, recordCpuUsageF4000_FP_SYSTEM, TestSize.Level1)
278 {
279 TestCpuUsage("-a -f 4000 -s fp -d 10", F4000_FP_CPU_LIMIT_SYSTEM, false);
280 }
281
282 /**
283 * @tc.name: recordCpuUsageF8000_FP_SYSTEM
284 * @tc.desc: test hiperf record system wide cpu usage within required limit
285 * @tc.type: FUNC
286 */
287 HWTEST_F(CpuUsageTest, recordCpuUsageF8000_FP_SYSTEM, TestSize.Level1)
288 {
289 TestCpuUsage("-a -f 8000 -s fp -d 10", F8000_FP_CPU_LIMIT_SYSTEM, false);
290 }
291
292 /**
293 * @tc.name: recordCpuUsageF100_DWARF_SYSTEM
294 * @tc.desc: test hiperf record system wide cpu usage within required limit
295 * @tc.type: FUNC
296 */
297 HWTEST_F(CpuUsageTest, recordCpuUsageF100_DWARF_SYSTEM, TestSize.Level1)
298 {
299 TestCpuUsage("-a -f 100 -s dwarf -d 10", F100_DWARF_CPU_LIMIT_SYSTEM, false);
300 }
301
302 /**
303 * @tc.name: recordCpuUsageF500_DWARF_SYSTEM
304 * @tc.desc: test hiperf record system wide cpu usage within required limit
305 * @tc.type: FUNC
306 */
307 HWTEST_F(CpuUsageTest, recordCpuUsageF500_DWARF_SYSTEM, TestSize.Level1)
308 {
309 TestCpuUsage("-a -f 500 -s dwarf -d 10", F500_DWARF_CPU_LIMIT_SYSTEM, false);
310 }
311
312 /**
313 * @tc.name: recordCpuUsageF1000_DWARF_SYSTEM
314 * @tc.desc: test hiperf record system wide cpu usage within required limit
315 * @tc.type: FUNC
316 */
317 HWTEST_F(CpuUsageTest, recordCpuUsageF1000_DWARF_SYSTEM, TestSize.Level1)
318 {
319 TestCpuUsage("-a -f 1000 -s dwarf -d 10", F1000_DWARF_CPU_LIMIT_SYSTEM, false);
320 }
321
322 /**
323 * @tc.name: recordCpuUsageF2000_DWARF_SYSTEM
324 * @tc.desc: test hiperf record system wide cpu usage within required limit
325 * @tc.type: FUNC
326 */
327 HWTEST_F(CpuUsageTest, recordCpuUsageF2000_DWARF_SYSTEM, TestSize.Level1)
328 {
329 TestCpuUsage("-a -f 2000 -s dwarf -d 10", F2000_DWARF_CPU_LIMIT_SYSTEM, false);
330 }
331
332 /**
333 * @tc.name: recordCpuUsageF4000_DWARF_SYSTEM
334 * @tc.desc: test hiperf record system wide cpu usage within required limit
335 * @tc.type: FUNC
336 */
337 HWTEST_F(CpuUsageTest, recordCpuUsageF4000_DWARF_SYSTEM, TestSize.Level1)
338 {
339 TestCpuUsage("-a -f 4000 -s dwarf -d 10", F4000_DWARF_CPU_LIMIT_SYSTEM, false);
340 }
341
342 /**
343 * @tc.name: recordCpuUsageF8000_DWARF_SYSTEM
344 * @tc.desc: test hiperf record system wide cpu usage within required limit
345 * @tc.type: FUNC
346 */
347 HWTEST_F(CpuUsageTest, recordCpuUsageF8000_DWARF_SYSTEM, TestSize.Level1)
348 {
349 TestCpuUsage("-a -f 8000 -s dwarf -d 10", F8000_DWARF_CPU_LIMIT_SYSTEM, false);
350 }
351
352 /**
353 * @tc.name: recordCpuUsageF100_FP_PROCESS
354 * @tc.desc: test hiperf record one process cpu usage within required limit
355 * @tc.type: FUNC
356 */
357 HWTEST_F(CpuUsageTest, recordCpuUsageF100_FP_PROCESS, TestSize.Level1)
358 {
359 TestCpuUsage("-f 100 -s fp -d 10", F100_FP_CPU_LIMIT_PROCESS, true);
360 }
361
362 /**
363 * @tc.name: recordCpuUsageF500_FP_PROCESS
364 * @tc.desc: test hiperf record one process cpu usage within required limit
365 * @tc.type: FUNC
366 */
367 HWTEST_F(CpuUsageTest, recordCpuUsageF500_FP_PROCESS, TestSize.Level1)
368 {
369 TestCpuUsage("-f 500 -s fp -d 10", F500_FP_CPU_LIMIT_PROCESS, true);
370 }
371
372 /**
373 * @tc.name: recordCpuUsageF1000_FP_PROCESS
374 * @tc.desc: test hiperf record one process cpu usage within required limit
375 * @tc.type: FUNC
376 */
377 HWTEST_F(CpuUsageTest, recordCpuUsageF1000_FP_PROCESS, TestSize.Level1)
378 {
379 TestCpuUsage("-f 1000 -s fp -d 10", F1000_FP_CPU_LIMIT_PROCESS, true);
380 }
381
382 /**
383 * @tc.name: recordCpuUsageF2000_FP_PROCESS
384 * @tc.desc: test hiperf record one process cpu usage within required limit
385 * @tc.type: FUNC
386 */
387 HWTEST_F(CpuUsageTest, recordCpuUsageF2000_FP_PROCESS, TestSize.Level1)
388 {
389 TestCpuUsage("-f 2000 -s fp -d 10", F2000_FP_CPU_LIMIT_PROCESS, true);
390 }
391
392 /**
393 * @tc.name: recordCpuUsageF4000_FP_PROCESS
394 * @tc.desc: test hiperf record one process cpu usage within required limit
395 * @tc.type: FUNC
396 */
397 HWTEST_F(CpuUsageTest, recordCpuUsageF4000_FP_PROCESS, TestSize.Level1)
398 {
399 TestCpuUsage("-f 4000 -s fp -d 10", F4000_FP_CPU_LIMIT_PROCESS, true);
400 }
401
402 /**
403 * @tc.name: recordCpuUsageF8000_FP_PROCESS
404 * @tc.desc: test hiperf record one process cpu usage within required limit
405 * @tc.type: FUNC
406 */
407 HWTEST_F(CpuUsageTest, recordCpuUsageF8000_FP_PROCESS, TestSize.Level1)
408 {
409 TestCpuUsage("-f 8000 -s fp -d 10", F8000_FP_CPU_LIMIT_PROCESS, true);
410 }
411
412 /**
413 * @tc.name: recordCpuUsageF100_DWARF_PROCESS
414 * @tc.desc: test hiperf record one process cpu usage within required limit
415 * @tc.type: FUNC
416 */
417 HWTEST_F(CpuUsageTest, recordCpuUsageF100_DWARF_PROCESS, TestSize.Level1)
418 {
419 TestCpuUsage("-f 100 -s dwarf -d 10", F100_DWARF_CPU_LIMIT_PROCESS, true);
420 }
421
422 /**
423 * @tc.name: recordCpuUsageF500_DWARF_PROCESS
424 * @tc.desc: test hiperf record one process cpu usage within required limit
425 * @tc.type: FUNC
426 */
427 HWTEST_F(CpuUsageTest, recordCpuUsageF500_DWARF_PROCESS, TestSize.Level1)
428 {
429 TestCpuUsage("-f 500 -s dwarf -d 10", F500_DWARF_CPU_LIMIT_PROCESS, true);
430 }
431
432 /**
433 * @tc.name: recordCpuUsageF1000_DWARF_PROCESS
434 * @tc.desc: test hiperf record one process cpu usage within required limit
435 * @tc.type: FUNC
436 */
437 HWTEST_F(CpuUsageTest, recordCpuUsageF1000_DWARF_PROCESS, TestSize.Level1)
438 {
439 TestCpuUsage("-f 1000 -s dwarf -d 10", F1000_DWARF_CPU_LIMIT_PROCESS, true);
440 }
441
442 /**
443 * @tc.name: recordCpuUsageF2000_DWARF_PROCESS
444 * @tc.desc: test hiperf record one process cpu usage within required limit
445 * @tc.type: FUNC
446 */
447 HWTEST_F(CpuUsageTest, recordCpuUsageF2000_DWARF_PROCESS, TestSize.Level1)
448 {
449 TestCpuUsage("-f 2000 -s dwarf -d 10", F2000_DWARF_CPU_LIMIT_PROCESS, true);
450 }
451
452 /**
453 * @tc.name: recordCpuUsageF4000_DWARF_PROCESS
454 * @tc.desc: test hiperf record one process cpu usage within required limit
455 * @tc.type: FUNC
456 */
457 HWTEST_F(CpuUsageTest, recordCpuUsageF4000_DWARF_PROCESS, TestSize.Level1)
458 {
459 TestCpuUsage("-f 4000 -s dwarf -d 10", F4000_DWARF_CPU_LIMIT_PROCESS, true);
460 }
461
462 /**
463 * @tc.name: recordCpuUsageF8000_DWARF_PROCESS
464 * @tc.desc: test hiperf record one process cpu usage within required limit
465 * @tc.type: FUNC
466 */
467 HWTEST_F(CpuUsageTest, recordCpuUsageF8000_DWARF_PROCESS, TestSize.Level1)
468 {
469 TestCpuUsage("-f 8000 -s dwarf -d 10", F8000_DWARF_CPU_LIMIT_PROCESS, true);
470 }
471 } // namespace HiPerf
472 } // namespace Developtools
473 } // namespace OHOS
474