1 /*
2 * Copyright (c) 2021-2022 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 #include "hiperf_client.h"
16 #include <sys/wait.h>
17 #include <algorithm>
18 #include <cinttypes>
19 #include <csignal>
20 #include <cstring>
21 #include <thread>
22 #include <poll.h>
23 #include <sys/prctl.h>
24 #include <unistd.h>
25 #include "hiperf_hilog.h"
26
27 using namespace std::chrono;
28 namespace OHOS {
29 namespace Developtools {
30 namespace HiPerf {
31 namespace HiperfClient {
32 const ssize_t ERRINFOLEN = 512;
SetOption(const std::string & name,bool enable)33 void RecordOption::SetOption(const std::string &name, bool enable)
34 {
35 auto it = std::find(args_.begin(), args_.end(), name);
36 if (enable) {
37 if (it == args_.end()) {
38 args_.emplace_back(name);
39 }
40
41 return;
42 }
43 if (it != args_.end()) {
44 args_.erase(it);
45 return;
46 }
47 }
48
SetOption(const std::string & name,int value)49 void RecordOption::SetOption(const std::string &name, int value)
50 {
51 auto it = std::find(args_.begin(), args_.end(), name);
52 if (it != args_.end()) {
53 it++;
54 *it = std::to_string(value);
55 return;
56 }
57
58 args_.emplace_back(name);
59 args_.emplace_back(std::to_string(value));
60 return;
61 }
62
SetOption(const std::string & name,const std::vector<int> & vInt)63 void RecordOption::SetOption(const std::string &name, const std::vector<int> &vInt)
64 {
65 auto it = std::find(args_.begin(), args_.end(), name);
66 if (vInt.empty()) {
67 if (it != args_.end()) {
68 it = args_.erase(it); // remove key
69 if (it != args_.end()) {
70 args_.erase(it); // remove value
71 }
72 }
73 return;
74 }
75
76 std::string str;
77 for (auto n : vInt) {
78 str.append(std::to_string(n));
79 str.append(",");
80 }
81 str.pop_back(); // remove the last ','
82
83 if (it != args_.end()) {
84 it++;
85 *it = str;
86 return;
87 }
88 args_.emplace_back(name);
89 args_.emplace_back(str);
90 }
91
SetOption(const std::string & name,const std::string & str)92 void RecordOption::SetOption(const std::string &name, const std::string &str)
93 {
94 auto it = std::find(args_.begin(), args_.end(), name);
95 if (str.empty()) {
96 if (it != args_.end()) {
97 args_.erase(it);
98 args_.erase(it); // remove value
99 }
100 return;
101 }
102 if (it != args_.end()) {
103 it++;
104 *it = str;
105 return;
106 }
107 args_.emplace_back(name);
108 args_.emplace_back(str);
109 }
110
SetOption(const std::string & name,const std::vector<std::string> & vStr)111 void RecordOption::SetOption(const std::string &name, const std::vector<std::string> &vStr)
112 {
113 auto it = std::find(args_.begin(), args_.end(), name);
114 if (vStr.empty()) {
115 if (it != args_.end()) {
116 args_.erase(it);
117 args_.erase(it); // remove value
118 }
119 return;
120 }
121
122 std::string str;
123 for (auto substr : vStr) {
124 str.append(substr);
125 str.append(",");
126 }
127 str.pop_back(); // remove the last ','
128
129 if (it != args_.end()) {
130 it++;
131 *it = str;
132 return;
133 }
134 args_.emplace_back(name);
135 args_.emplace_back(str);
136 }
137
SetTargetSystemWide(bool enable)138 void RecordOption::SetTargetSystemWide(bool enable)
139 {
140 SetOption(ArgTargetSystemWide, enable);
141 }
142
SetCompressData(bool enable)143 void RecordOption::SetCompressData(bool enable)
144 {
145 SetOption(ArgCompressData, enable);
146 }
147
SetSelectCpus(const std::vector<int> & cpus)148 void RecordOption::SetSelectCpus(const std::vector<int> &cpus)
149 {
150 SetOption(ArgSelectCpus, cpus);
151 }
152
SetTimeStopSec(int timeStopSec)153 void RecordOption::SetTimeStopSec(int timeStopSec)
154 {
155 this->timeSpec_ = true;
156 SetOption(ArgTimeStopSec, timeStopSec);
157 }
158
SetFrequency(int frequency)159 void RecordOption::SetFrequency(int frequency)
160 {
161 SetOption(ArgFrequency, frequency);
162 }
163
SetPeriod(int period)164 void RecordOption::SetPeriod(int period)
165 {
166 SetOption(ArgPeriod, period);
167 }
168
SetSelectEvents(const std::vector<std::string> & selectEvents)169 void RecordOption::SetSelectEvents(const std::vector<std::string> &selectEvents)
170 {
171 SetOption(ArgSelectEvents, selectEvents);
172 }
173
SetSelectGroups(const std::vector<std::string> & selectGroups)174 void RecordOption::SetSelectGroups(const std::vector<std::string> &selectGroups)
175 {
176 SetOption(ArgSelectGroups, selectGroups);
177 }
178
SetNoInherit(bool enable)179 void RecordOption::SetNoInherit(bool enable)
180 {
181 SetOption(ArgNoInherit, enable);
182 }
183
SetSelectPids(const std::vector<pid_t> & selectPids)184 void RecordOption::SetSelectPids(const std::vector<pid_t> &selectPids)
185 {
186 SetOption(ArgSelectPids, selectPids);
187 }
188
SetCallStackSamplingConfigs(int duration)189 void RecordOption::SetCallStackSamplingConfigs(int duration)
190 {
191 if (duration <= 0) {
192 duration = DEFAULT_DURATION_TIME;
193 }
194 RecordOption opt;
195 SetSelectEvents(opt.GetSelectEvents());
196 SetTimeStopSec(duration);
197 SetFrequency(DEFAULT_FREQUENCY_TIME);
198 SetCallGraph("fp");
199 }
200
SetSelectTids(const std::vector<pid_t> & selectTids)201 void RecordOption::SetSelectTids(const std::vector<pid_t> &selectTids)
202 {
203 SetOption(ArgSelectTids, selectTids);
204 }
205
SetExcludePerf(bool excludePerf)206 void RecordOption::SetExcludePerf(bool excludePerf)
207 {
208 SetOption(ArgExcludePerf, excludePerf);
209 }
210
SetCpuPercent(int cpuPercent)211 void RecordOption::SetCpuPercent(int cpuPercent)
212 {
213 SetOption(ArgCpuPercent, cpuPercent);
214 }
215
SetOffCPU(bool offCPU)216 void RecordOption::SetOffCPU(bool offCPU)
217 {
218 SetOption(ArgOffCPU, offCPU);
219 }
220
SetCallGraph(const std::string & callGraph)221 void RecordOption::SetCallGraph(const std::string &callGraph)
222 {
223 SetOption(ArgCallGraph, callGraph);
224 }
225
SetDelayUnwind(bool delayUnwind)226 void RecordOption::SetDelayUnwind(bool delayUnwind)
227 {
228 SetOption(ArgDelayUnwind, delayUnwind);
229 }
230
SetDisableUnwind(bool disableUnwind)231 void RecordOption::SetDisableUnwind(bool disableUnwind)
232 {
233 SetOption(ArgDisableUnwind, disableUnwind);
234 }
235
SetDisableCallstackMerge(bool disableCallstackMerge)236 void RecordOption::SetDisableCallstackMerge(bool disableCallstackMerge)
237 {
238 SetOption(ArgDisableCallstackMerge, disableCallstackMerge);
239 }
240
SetSymbolDir(const std::string & symbolDir_)241 void RecordOption::SetSymbolDir(const std::string &symbolDir_)
242 {
243 SetOption(ArgSymbolDir, symbolDir_);
244 }
245
SetDataLimit(const std::string & limit)246 void RecordOption::SetDataLimit(const std::string &limit)
247 {
248 SetOption(ArgDataLimit, limit);
249 }
250
SetAppPackage(const std::string & appPackage)251 void RecordOption::SetAppPackage(const std::string &appPackage)
252 {
253 SetOption(ArgAppPackage, appPackage);
254 }
255
SetClockId(const std::string & clockId)256 void RecordOption::SetClockId(const std::string &clockId)
257 {
258 SetOption(ArgClockId, clockId);
259 }
260
SetVecBranchSampleTypes(const std::vector<std::string> & vecBranchSampleTypes)261 void RecordOption::SetVecBranchSampleTypes(const std::vector<std::string> &vecBranchSampleTypes)
262 {
263 SetOption(ArgVecBranchSampleTypes, vecBranchSampleTypes);
264 }
265
SetMmapPages(int mmapPages)266 void RecordOption::SetMmapPages(int mmapPages)
267 {
268 SetOption(ArgMmapPages, mmapPages);
269 }
270
Client(const std::string & outputDir)271 Client::Client(const std::string &outputDir)
272 {
273 HIPERF_HILOGD(MODULE_CPP_API, "%" HILOG_PUBLIC "s default init with %" HILOG_PUBLIC "s\n",
274 __FUNCTION__, outputDir.c_str());
275 Setup(outputDir);
276 }
277
Setup(std::string outputDir)278 bool Client::Setup(std::string outputDir)
279 {
280 std::string CurrentCommandPath = CurrentPath + HiperfCommandName;
281 std::string SystemCommandPath = SystemBinPath + HiperfCommandName;
282 std::string TempCommandPath = TempBinPath + HiperfCommandName;
283
284 if (!outputDir.empty() && outputDir.back() != '/') {
285 outputDir.push_back('/');
286 }
287 HIPERF_HILOGD(MODULE_CPP_API, "outputDir setup to %" HILOG_PUBLIC "s\n", outputDir.c_str());
288
289 // found command path
290 if (access(CurrentCommandPath.c_str(), X_OK) == 0) {
291 executeCommandPath_ = CurrentCommandPath;
292 } else if (access(TempCommandPath.c_str(), X_OK) == 0) {
293 executeCommandPath_ = TempCommandPath;
294 } else if (access(SystemCommandPath.c_str(), X_OK) == 0) {
295 executeCommandPath_ = SystemCommandPath;
296 } else {
297 HIPERF_HILOGD(MODULE_CPP_API, "no hiperf command found\n");
298 return ready_;
299 }
300
301 // check output path
302 // found command path
303 if (access(outputDir.c_str(), W_OK) == 0) {
304 outputDir_ = outputDir;
305 } else if (access(CurrentPath.c_str(), W_OK) == 0) {
306 outputDir_ = CurrentPath;
307 } else {
308 HIPERF_HILOGD(MODULE_CPP_API, "no writeable output path found\n");
309 return ready_;
310 }
311 outputFileName_ = PerfDataName;
312
313 myPid_ = getpid();
314
315 // every thing check ok
316 ready_ = true;
317
318 return ready_;
319 }
320
~Client()321 Client::~Client()
322 {
323 KillChild();
324 }
325
IsReady()326 bool Client::IsReady()
327 {
328 return ready_;
329 }
330
SetDebugMode()331 void Client::SetDebugMode()
332 {
333 debug_ = true;
334 }
335
SetDebugMuchMode()336 void Client::SetDebugMuchMode()
337 {
338 debugMuch_ = true;
339 }
340
Start()341 bool Client::Start()
342 {
343 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
344
345 std::vector<std::string> args;
346 args.push_back("-p");
347 args.push_back(std::to_string(getpid()));
348 return Start(args);
349 }
350
PrepareExecCmd(std::vector<std::string> & cmd)351 void Client::PrepareExecCmd(std::vector<std::string> &cmd)
352 {
353 cmd.clear();
354 cmd.emplace_back(executeCommandPath_);
355
356 if (debug_) {
357 cmd.emplace_back(ArgDebug);
358 } else if (debugMuch_) {
359 cmd.emplace_back(ArgDebugMuch);
360 }
361
362 if (hilog_) {
363 cmd.emplace_back(ArgHilog);
364 }
365
366 cmd.emplace_back(CommandRecord);
367 cmd.emplace_back(ArgOutputPath);
368 cmd.emplace_back(GetOutputPerfDataPath());
369 }
370
GetExecCmd(std::vector<std::string> & cmd,int pipeIn,int pipeOut,const std::vector<std::string> & args)371 void Client::GetExecCmd(std::vector<std::string> &cmd, int pipeIn, int pipeOut,
372 const std::vector<std::string> &args)
373 {
374 PrepareExecCmd(cmd);
375 cmd.emplace_back(ArgPipeInput);
376 cmd.emplace_back(std::to_string(pipeIn));
377 cmd.emplace_back(ArgPipeOutput);
378 cmd.emplace_back(std::to_string(pipeOut));
379
380 cmd.insert(cmd.end(), args.begin(), args.end());
381 }
382
GetExecCmd(std::vector<std::string> & cmd,const std::vector<std::string> & args)383 void Client::GetExecCmd(std::vector<std::string> &cmd,
384 const std::vector<std::string> &args)
385 {
386 PrepareExecCmd(cmd);
387
388 cmd.insert(cmd.end(), args.begin(), args.end());
389 }
390
Start(const std::vector<std::string> & args)391 bool Client::Start(const std::vector<std::string> &args)
392 {
393 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
394 if (!ready_) {
395 HIPERF_HILOGD(MODULE_CPP_API, "Client:hiperf not ready.\n");
396 return false;
397 }
398
399 int clientToServerFd[2];
400 int serverToClientFd[2];
401 if (pipe(clientToServerFd) != 0) {
402 char errInfo[ERRINFOLEN] = { 0 };
403 strerror_r(errno, errInfo, ERRINFOLEN);
404 HIPERF_HILOGD(MODULE_CPP_API, "failed to create pipe: %" HILOG_PUBLIC "s", errInfo);
405 return false;
406 } else if (pipe(serverToClientFd) != 0) {
407 char errInfo[ERRINFOLEN] = { 0 };
408 strerror_r(errno, errInfo, ERRINFOLEN);
409 HIPERF_HILOGD(MODULE_CPP_API, "failed to create pipe: %" HILOG_PUBLIC "s", errInfo);
410 close(clientToServerFd[PIPE_READ]);
411 close(clientToServerFd[PIPE_WRITE]);
412 return false;
413 }
414
415 hperfPid_ = fork();
416 if (hperfPid_ == -1) {
417 char errInfo[ERRINFOLEN] = { 0 };
418 strerror_r(errno, errInfo, ERRINFOLEN);
419 HIPERF_HILOGD(MODULE_CPP_API, "failed to fork: %" HILOG_PUBLIC "s", errInfo);
420 close(clientToServerFd[PIPE_READ]);
421 close(clientToServerFd[PIPE_WRITE]);
422 close(serverToClientFd[PIPE_READ]);
423 close(serverToClientFd[PIPE_WRITE]);
424 return false;
425 } else if (hperfPid_ == 0) {
426 // child process
427 prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
428 close(clientToServerFd[PIPE_WRITE]);
429 close(serverToClientFd[PIPE_READ]);
430
431 std::vector<std::string> cmd;
432 GetExecCmd(cmd, clientToServerFd[PIPE_READ], serverToClientFd[PIPE_WRITE], args);
433 ChildRunExecv(cmd);
434 } else {
435 // parent process
436 close(clientToServerFd[PIPE_READ]);
437 close(serverToClientFd[PIPE_WRITE]);
438
439 clientToServerFd_ = clientToServerFd[PIPE_WRITE];
440 serverToClientFd_ = serverToClientFd[PIPE_READ];
441 }
442 using namespace std::chrono_literals;
443 if (!WaitCommandReply(1000ms)) {
444 HIPERF_HILOGD(MODULE_CPP_API, "start failed . lets kill it");
445 KillChild();
446 return false;
447 }
448 return true;
449 }
450
Start(const RecordOption & option)451 bool Client::Start(const RecordOption &option)
452 {
453 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
454 if (!option.GetOutputFileName().empty()) {
455 outputFileName_ = option.GetOutputFileName();
456 }
457 if (option.IsTimeSpecified()) {
458 return RunHiperfCmdSync(option);
459 }
460 return Start(option.GetOptionVecString());
461 }
462
ChildRunExecv(std::vector<std::string> & cmd)463 void Client::ChildRunExecv(std::vector<std::string> &cmd)
464 {
465 // conver vector to array for execvp()
466 char *argv[cmd.size() + SIZE_ARGV_TAIL];
467 size_t i = 0;
468 for (i = 0; i < cmd.size(); ++i) {
469 HIPERF_HILOGD(MODULE_CPP_API, "args %" HILOG_PUBLIC "zu : %" HILOG_PUBLIC "s", i,
470 cmd[i].c_str());
471 argv[i] = cmd[i].data();
472 }
473 argv[i] = nullptr;
474
475 execv(argv[0], argv);
476
477 // never reach the following line, unless calling of execv function failed.
478 char errInfo[ERRINFOLEN] = { 0 };
479 strerror_r(errno, errInfo, ERRINFOLEN);
480 HIPERF_HILOGD(MODULE_CPP_API,
481 "failed to call exec: '%" HILOG_PUBLIC "s' %" HILOG_PUBLIC "s\n",
482 executeCommandPath_.c_str(), errInfo);
483 exit(EXIT_FAILURE); // EXIT_FAILURE 1
484 }
485
ParentWait(pid_t & wpid,int & childStatus)486 bool Client::ParentWait(pid_t &wpid, int &childStatus)
487 {
488 bool ret = false;
489 do {
490 // blocking...
491 int option;
492 #ifdef WCONTINUED
493 option = WUNTRACED | WCONTINUED;
494 #else
495 option = WUNTRACED;
496 #endif
497 wpid = waitpid(hperfPid_, &childStatus, option);
498 if (wpid == -1) {
499 perror("waitpid");
500 exit(EXIT_FAILURE);
501 }
502
503 if (WIFEXITED(childStatus)) {
504 // child normally exit
505 // WEXITSTATUS(childStatus) value :
506 // true -> Calling of execv func successed, and recording finished
507 // and child will return the value of recording process's retVal
508 // false -> Calling of execv func failed, child will output errInfo
509 ret = WEXITSTATUS(childStatus) == 0 ? true : false;
510 HIPERF_HILOGD(MODULE_CPP_API,
511 "Hiperf Api Child normally exit Calling of execv : '%" HILOG_PUBLIC "s' \n",
512 ret ? "success" : "failed");
513 return ret;
514 } else if (WIFSIGNALED(childStatus)) [[unlikely]] {
515 // child was killed by SIGKILL
516 HIPERF_HILOGD(MODULE_CPP_API, "Hiperf recording process was killed by signal SIGKILL\n");
517 ret = false;
518 return ret;
519 } else if (WIFSTOPPED(childStatus)) [[unlikely]] {
520 // child was stopped by SIGSTOP, and waiting for SIGCONT
521 HIPERF_HILOGD(MODULE_CPP_API, "Hiperf recording process was stopped by signal SIGSTOP\n");
522 #ifdef WIFCONTINUED
523 } else if (WIFCONTINUED(childStatus)) {
524 // child was continued by SIGCONT
525 HIPERF_HILOGD(MODULE_CPP_API, "Hiperf recording process was continued\n by SIGCONT");
526 #endif
527 } else [[unlikely]] {
528 // non-standard case, may never happen
529 HIPERF_HILOGD(MODULE_CPP_API, "Hiperf recording process Unexpected status\n");
530 }
531 } while (!WIFEXITED(childStatus) && !WIFSIGNALED(childStatus));
532
533 // normal exit.
534 if (WIFEXITED(childStatus)) {
535 ret = WEXITSTATUS(childStatus) == HIPERF_EXIT_CODE;
536 } else {
537 // signal exit, means Hiperf recording process may occur some runtime errors.
538 HIPERF_HILOGD(MODULE_CPP_API,
539 "Hiperf recording occurs some runtime errors, end with signal : %"
540 HILOG_PUBLIC "d, exit status : %" HILOG_PUBLIC "d\n",
541 WIFSIGNALED(childStatus), WEXITSTATUS(childStatus));
542 ret = false;
543 }
544 return ret;
545 }
546
547
RunHiperfCmdSync(const RecordOption & option)548 bool Client::RunHiperfCmdSync(const RecordOption &option)
549 {
550 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
551 if (!ready_) {
552 HIPERF_HILOGD(MODULE_CPP_API, "Client:hiperf not ready.\n");
553 return false;
554 }
555 const std::vector<std::string> &args = option.GetOptionVecString();
556
557 pid_t wpid;
558 int childStatus;
559 bool ret = false;
560 hperfPid_ = fork();
561 if (hperfPid_ == -1) {
562 char errInfo[ERRINFOLEN] = { 0 };
563 strerror_r(errno, errInfo, ERRINFOLEN);
564 HIPERF_HILOGD(MODULE_CPP_API, "failed to fork: %" HILOG_PUBLIC "s", errInfo);
565 return false;
566 } else if (hperfPid_ == 0) {
567 // child execute
568 std::vector<std::string> cmd;
569 GetExecCmd(cmd, args);
570 ChildRunExecv(cmd);
571 } else {
572 ret = ParentWait(wpid, childStatus);
573 }
574 return ret;
575 }
576
WaitCommandReply(std::chrono::milliseconds timeOut)577 bool Client::WaitCommandReply(std::chrono::milliseconds timeOut)
578 {
579 std::string reply;
580 struct pollfd pollFd;
581 pollFd.fd = serverToClientFd_;
582 pollFd.events = POLLIN;
583 pollFd.revents = 0;
584
585 // wait some data
586 int polled = poll(&pollFd, 1, timeOut.count());
587 if (polled > 0) {
588 while (true) {
589 char c;
590 ssize_t result = TEMP_FAILURE_RETRY(read(serverToClientFd_, &c, 1));
591 if (result <= 0) {
592 HIPERF_HILOGD(MODULE_CPP_API, "read failed from pipe");
593 return false; // read fial means not ok
594 }
595
596 reply.push_back(c);
597 if (c == '\n') {
598 break;
599 }
600 }
601 } else if (polled == 0) {
602 HIPERF_HILOGD(MODULE_CPP_API, "Client:command no response %" HILOG_PUBLIC "" PRIu64 ".\n",
603 (uint64_t)timeOut.count());
604 } else {
605 HIPERF_HILOGD(MODULE_CPP_API, "Client:command poll failed.\n");
606 }
607 HIPERF_HILOGD(MODULE_CPP_API, "Client:new reply:%" HILOG_PUBLIC "s\n", reply.c_str());
608 if (reply == ReplyOK) {
609 return true;
610 } else {
611 return false;
612 }
613 }
614
KillChild()615 void Client::KillChild()
616 {
617 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
618 if (clientToServerFd_ != -1) {
619 close(clientToServerFd_);
620 }
621 if (serverToClientFd_ != -1) {
622 close(serverToClientFd_);
623 }
624 if (hperfPid_ > 0) {
625 kill(hperfPid_, SIGKILL);
626 }
627 }
628
SendCommandAndWait(const std::string & cmd)629 bool Client::SendCommandAndWait(const std::string &cmd)
630 {
631 if (clientToServerFd_ == -1) {
632 HIPERF_HILOGD(MODULE_CPP_API, "fd not ready. maybe not called start.");
633 return false;
634 }
635 size_t size = write(clientToServerFd_, cmd.c_str(), cmd.size());
636 HIPERF_HILOGD(MODULE_CPP_API,
637 "Client:%" HILOG_PUBLIC "s -> %" HILOG_PUBLIC "d : %" HILOG_PUBLIC "zd\n",
638 cmd.c_str(), clientToServerFd_, size);
639 if (size == cmd.size()) {
640 return WaitCommandReply();
641 } else {
642 return false;
643 }
644 }
645
Pause()646 bool Client::Pause()
647 {
648 if (!ready_) {
649 HIPERF_HILOGD(MODULE_CPP_API, "Client:hiperf not ready.\n");
650 return false;
651 }
652 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
653 if (SendCommandAndWait(ReplyPause)) {
654 return true;
655 }
656 return false;
657 }
658
Resume()659 bool Client::Resume()
660 {
661 if (!ready_) {
662 HIPERF_HILOGD(MODULE_CPP_API, "Client:hiperf not ready.\n");
663 return false;
664 }
665 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
666 if (SendCommandAndWait(ReplyResume)) {
667 return true;
668 }
669 return false;
670 }
671
Stop()672 bool Client::Stop()
673 {
674 if (!ready_) {
675 HIPERF_HILOGD(MODULE_CPP_API, "Client:hiperf not ready.\n");
676 return false;
677 }
678 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
679 if (SendCommandAndWait(ReplyStop)) {
680 // wait sampling process exit really
681 while (SendCommandAndWait(ReplyCheck)) {
682 std::this_thread::sleep_for(1s);
683 }
684 return true;
685 }
686 return false;
687 }
688
EnableHilog()689 void Client::EnableHilog()
690 {
691 HIPERF_HILOGD(MODULE_CPP_API, "Client:%" HILOG_PUBLIC "s\n", __FUNCTION__);
692 hilog_ = true;
693 }
694 } // namespace HiperfClient
695 } // namespace HiPerf
696 } // namespace Developtools
697 } // namespace OHOS
698