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