• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "perf_pipe.h"
17 #include "hiperf_client.h"
18 #include "ipc_utilities.h"
19 #include "utilities.h"
20 #if defined(is_ohos) && is_ohos
21 #include "hiperf_hilog.h"
22 #endif
23 
24 using namespace std::chrono;
25 namespace OHOS {
26 namespace Developtools {
27 namespace HiPerf {
28 const std::string RECORD_CONTROL_FIFO_FILE_C2S = "/data/log/hiperflog/.hiperf_record_control_c2s";
29 const std::string RECORD_CONTROL_FIFO_FILE_S2C = "/data/log/hiperflog/.hiperf_record_control_s2c";
30 const std::string STAT_CONTROL_FIFO_FILE_C2S = "/data/log/hiperflog/.hiperf_stat_control_c2s";
31 const std::string STAT_CONTROL_FIFO_FILE_S2C = "/data/log/hiperflog/.hiperf_stat_control_s2c";
32 const std::chrono::milliseconds CONTROL_WAITREPY_TIMEOUT = 2000ms;
33 const std::chrono::milliseconds CONTROL_WAITREPY_TIMEOUT_CHECK = 1000ms;
34 static constexpr uint64_t CHECK_WAIT_TIME_MS = 200;
35 static constexpr uint32_t MAX_CLIENT_OUTPUT_WAIT_COUNT = 240;
36 
SetFifoFileName(const CommandType & commandType,std::string & controlCmd,std::string & fifoFileC2S,std::string & fifoFileS2C)37 void PerfPipe::SetFifoFileName(const CommandType& commandType, std::string& controlCmd,
38     std::string& fifoFileC2S, std::string& fifoFileS2C)
39 {
40     if (commandType == CommandType::RECORD) {
41         fifoFileC2S_ = RECORD_CONTROL_FIFO_FILE_C2S;
42         fifoFileS2C_ = RECORD_CONTROL_FIFO_FILE_S2C;
43         perfCmd_ = "sampling";
44     } else if (commandType == CommandType::STAT) {
45         fifoFileC2S_ = STAT_CONTROL_FIFO_FILE_C2S;
46         fifoFileS2C_ = STAT_CONTROL_FIFO_FILE_S2C;
47         perfCmd_ = "counting";
48     }
49     fifoFileC2S = fifoFileC2S_;
50     fifoFileS2C = fifoFileS2C_;
51     controlCmd_ = controlCmd;
52     HLOGD("C2S:%s, S2C:%s", fifoFileC2S.c_str(), fifoFileS2C.c_str());
53     HIPERF_HILOGD(MODULE_DEFAULT, "[SetFifoFileName] C2S:%{public}s, S2C:%{public}s",
54         fifoFileC2S_.c_str(), fifoFileS2C.c_str());
55 }
56 
RemoveFifoFile()57 void PerfPipe::RemoveFifoFile()
58 {
59     char errInfo[ERRINFOLEN] = { 0 };
60     if (remove(fifoFileC2S_.c_str()) != 0) {
61         strerror_r(errno, errInfo, ERRINFOLEN);
62         HLOGE("remove %s failed, errno:(%d:%s)", fifoFileC2S_.c_str(), errno, errInfo);
63         HIPERF_HILOGE(MODULE_DEFAULT, "remove %{public}s failed, errno:(%{public}d:%{public}s)",
64             fifoFileC2S_.c_str(), errno, errInfo);
65     }
66     if (remove(fifoFileS2C_.c_str()) != 0) {
67         strerror_r(errno, errInfo, ERRINFOLEN);
68         HLOGE("remove %s failed, errno:(%d:%s)", fifoFileS2C_.c_str(), errno, errInfo);
69         HIPERF_HILOGE(MODULE_DEFAULT, "remove %{public}s failed, errno:(%{public}d:%{public}s)",
70             fifoFileS2C_.c_str(), errno, errInfo);
71     }
72 }
73 
CreateFifoFile()74 bool PerfPipe::CreateFifoFile()
75 {
76     char errInfo[ERRINFOLEN] = { 0 };
77     const mode_t fifoMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
78     std::string tempPath("/data/log/hiperflog/");
79     if (!IsDirectoryExists(tempPath)) {
80         HIPERF_HILOGI(MODULE_DEFAULT, "%{public}s not exist.", tempPath.c_str());
81         if (!CreateDirectory(tempPath, HIPERF_FILE_PERM_770)) {
82             HIPERF_HILOGI(MODULE_DEFAULT, "create %{public}s failed.", tempPath.c_str());
83         }
84     }
85     if (mkfifo(fifoFileS2C_.c_str(), fifoMode) != 0 ||
86         mkfifo(fifoFileC2S_.c_str(), fifoMode) != 0) {
87         if (errno == EEXIST) {
88             printf("another %s service is running.\n", perfCmd_.c_str());
89         } else {
90             RemoveFifoFile();
91         }
92         strerror_r(errno, errInfo, ERRINFOLEN);
93         HLOGE("create fifo file failed. %d:%s", errno, errInfo);
94         return false;
95     }
96     return true;
97 }
98 
SendFifoAndWaitReply(const std::string & cmd,const std::chrono::milliseconds & timeOut)99 bool PerfPipe::SendFifoAndWaitReply(const std::string &cmd, const std::chrono::milliseconds &timeOut)
100 {
101     // need open for read first, because server maybe send reply before client wait to read
102     char errInfo[ERRINFOLEN] = { 0 };
103     int fdRead = open(fifoFileS2C_.c_str(), O_RDONLY | O_NONBLOCK);
104     if (fdRead == -1) {
105         HLOGE("can not open fifo file(%s)", fifoFileS2C_.c_str());
106         HIPERF_HILOGE(MODULE_DEFAULT,
107             "[SendFifoAndWaitReply] can not open fifo file: %{public}s, errno:(%{public}d:%{public}s)",
108             fifoFileS2C_.c_str(), errno, errInfo);
109         return false;
110     }
111     int fdWrite = open(fifoFileC2S_.c_str(), O_WRONLY | O_NONBLOCK);
112     if (fdWrite == -1) {
113         HLOGE("can not open fifo file(%s)", fifoFileC2S_.c_str());
114         HIPERF_HILOGE(MODULE_DEFAULT,
115             "[SendFifoAndWaitReply] can not open fifo file: %{public}s, errno:(%{public}d:%{public}s)",
116             fifoFileC2S_.c_str(), errno, errInfo);
117         close(fdRead);
118         return false;
119     }
120     ssize_t size = write(fdWrite, cmd.c_str(), cmd.size());
121     if (size != static_cast<ssize_t>(cmd.size())) {
122         HLOGE("failed to write fifo file(%s) command(%s)", fifoFileC2S_.c_str(), cmd.c_str());
123         HIPERF_HILOGE(MODULE_DEFAULT, "failed to write fifo file(%{public}s) command(%{public}s).",
124             fifoFileC2S_.c_str(), cmd.c_str());
125         close(fdWrite);
126         close(fdRead);
127         return false;
128     }
129     close(fdWrite);
130 
131     bool ret = WaitFifoReply(fdRead, timeOut);
132     close(fdRead);
133     return ret;
134 }
135 
WaitFifoReply(const int fd,const std::chrono::milliseconds & timeOut)136 bool PerfPipe::WaitFifoReply(const int fd, const std::chrono::milliseconds &timeOut)
137 {
138     std::string reply;
139     WaitFifoReply(fd, timeOut, reply);
140     HIPERF_HILOGI(MODULE_DEFAULT, "[WaitFifoReply] WaitFifoReply reply:(%{public}s)", reply.c_str());
141     return reply == HiperfClient::ReplyOK;
142 }
143 
WaitFifoReply(const int fd,const std::chrono::milliseconds & timeOut,std::string & reply)144 void PerfPipe::WaitFifoReply(const int fd, const std::chrono::milliseconds &timeOut, std::string& reply)
145 {
146     struct pollfd pollFd {
147         fd, POLLIN, 0
148     };
149     int polled = poll(&pollFd, 1, timeOut.count());
150     reply.clear();
151     if (polled > 0) {
152         bool exitLoop = false;
153         while (!exitLoop) {
154             char c;
155             ssize_t result = TEMP_FAILURE_RETRY(read(fd, &c, 1));
156             if (result <= 0) {
157                 HLOGE("[WaitFifoReply] read from fifo file(%s) failed", fifoFileS2C_.c_str());
158                 HIPERF_HILOGE(MODULE_DEFAULT, "[WaitFifoReply] read from fifo file(%{public}s) failed",
159                     fifoFileS2C_.c_str());
160                 exitLoop = true;
161             }
162             reply.push_back(c);
163             if (c == '\n') {
164                 exitLoop = true;
165             }
166         }
167     } else if (polled == 0) {
168         HLOGD("[WaitFifoReply] wait fifo file(%s) timeout", fifoFileS2C_.c_str());
169         HIPERF_HILOGD(MODULE_DEFAULT, "[WaitFifoReply] wait fifo file(%{public}s) timeout", fifoFileS2C_.c_str());
170     } else {
171         HLOGD("[WaitFifoReply] wait fifo file(%s) failed", fifoFileS2C_.c_str());
172         HIPERF_HILOGD(MODULE_DEFAULT, "[WaitFifoReply] wait fifo file(%{public}s) failed", fifoFileS2C_.c_str());
173     }
174 }
175 
SetOutPutEnd(const bool outputEnd)176 void PerfPipe::SetOutPutEnd(const bool outputEnd)
177 {
178     outputEnd_ = outputEnd;
179 }
180 
ProcessStopCommand(const bool ret)181 void PerfPipe::ProcessStopCommand(const bool ret)
182 {
183     if (ret) {
184         // wait sampling process exit really
185         static constexpr uint64_t waitCheckSleepMs = 200;
186         std::this_thread::sleep_for(milliseconds(waitCheckSleepMs));
187         while (SendFifoAndWaitReply(HiperfClient::ReplyCheck, CONTROL_WAITREPY_TIMEOUT_CHECK)) {
188             std::this_thread::sleep_for(milliseconds(waitCheckSleepMs));
189         }
190         HLOGI("wait reply check end.");
191     }
192 
193     RemoveFifoFile();
194 }
195 
ProcessOutputCommand(bool ret)196 void PerfPipe::ProcessOutputCommand(bool ret)
197 {
198     if (!ret) {
199         HLOGI("send fifo and wait repoy fail");
200         HIPERF_HILOGI(MODULE_DEFAULT, "send fifo and wait repoy fail");
201         return;
202     }
203 
204     std::this_thread::sleep_for(milliseconds(CHECK_WAIT_TIME_MS));
205     uint32_t outputFailCount = 0;
206     while (!outputEnd_) {
207         ret = SendFifoAndWaitReply(HiperfClient::ReplyOutputCheck, CONTROL_WAITREPY_TIMEOUT_CHECK);
208         if (outputFailCount++ > MAX_CLIENT_OUTPUT_WAIT_COUNT || ret) {
209             break;
210         }
211         std::this_thread::sleep_for(milliseconds(CHECK_WAIT_TIME_MS));
212     }
213 }
214 
ProcessControlCmd()215 bool PerfPipe::ProcessControlCmd()
216 {
217     bool ret = false;
218     if (controlCmd_ == CONTROL_CMD_START) {
219         ret = SendFifoAndWaitReply(HiperfClient::ReplyStart, CONTROL_WAITREPY_TIMEOUT);
220     } else if (controlCmd_ == CONTROL_CMD_RESUME) {
221         ret = SendFifoAndWaitReply(HiperfClient::ReplyResume, CONTROL_WAITREPY_TIMEOUT);
222     } else if (controlCmd_ == CONTROL_CMD_PAUSE) {
223         ret = SendFifoAndWaitReply(HiperfClient::ReplyPause, CONTROL_WAITREPY_TIMEOUT);
224     } else if (controlCmd_ == CONTROL_CMD_STOP) {
225         ret = SendFifoAndWaitReply(HiperfClient::ReplyStop, CONTROL_WAITREPY_TIMEOUT);
226         if (!ret) {
227             ret = SendFifoAndWaitReply(HiperfClient::ReplyStop, CONTROL_WAITREPY_TIMEOUT);
228         }
229         ProcessStopCommand(ret);
230     } else if (controlCmd_ == CONTROL_CMD_OUTPUT) {
231         ret = SendFifoAndWaitReply(HiperfClient::ReplyOutput, CONTROL_WAITREPY_TIMEOUT);
232         ProcessOutputCommand(ret);
233     }
234     if (ret) {
235         printf("%s %s success.\n", controlCmd_.c_str(), perfCmd_.c_str());
236         HIPERF_HILOGI(MODULE_DEFAULT, "[ProcessControlCmd] %{public}s %{public}s success.",
237             controlCmd_.c_str(), perfCmd_.c_str());
238     } else {
239         printf("%s %s failed.\n", controlCmd_.c_str(), perfCmd_.c_str());
240         HIPERF_HILOGI(MODULE_DEFAULT, "[ProcessControlCmd] %{public}s %{public}s failed.",
241             controlCmd_.c_str(), perfCmd_.c_str());
242     }
243     return ret;
244 }
245 } // namespace HiPerf
246 } // namespace Developtools
247 } // namespace OHOS
248