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