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