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