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