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