1 /*
2 * Copyright (c) 2023 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 "eu/rtg_ioctl.h"
17
18 #include <sstream>
19 #include <iomanip>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <cstring>
23 #include <climits>
24 #include <sys/syscall.h>
25 #include <sys/ioctl.h>
26
27 #include "ffrt_trace.h"
28 #include "dfx/log/ffrt_log_api.h"
29
30 constexpr int RTG_FRAME_START = 1;
31 constexpr int RTG_FRAME_END = 2;
32
33 constexpr int RTG_IPC_MAGIC = 0XBC;
34 constexpr int RTG_IPC_CMDID = 0xCD;
35 #define RTG_IPC_CMD _IOWR(RTG_IPC_MAGIC, RTG_IPC_CMDID, class RTGMsg)
36
37 namespace ffrt {
38 enum RTGCtrlCmd {
39 CMD_CREATE_RTG,
40 CMD_RELEASE_RTG,
41 CMD_ADD_RTG_THREAD,
42 CMD_DEL_RTG_THREAD,
43 CMD_SET_GROUP_UTIL,
44 CMD_SET_GROUP_FREQ,
45 CMD_GET_THREAD_LOAD,
46 CMD_GET_GROUP_LOAD,
47 CMD_SET_GROUP_WINDOW_SIZE,
48 CMD_SET_GROUP_WINDOW_ROLLOVER,
49 CMD_SET_PREFERRED_CLUSTER,
50 CMD_SET_INVALID_INTERVAL,
51 CMD_ID_MAX,
52 };
53
FromatRTGCtrlCmd(uint32_t cmd)54 static const char* FromatRTGCtrlCmd(uint32_t cmd)
55 {
56 static const char* str[] = {
57 "CMD_CREATE_RTG",
58 "CMD_RELEASE_RTG",
59 "CMD_ADD_RTG_THREAD",
60 "CMD_DEL_RTG_THREAD",
61 "CMD_SET_GROUP_UTIL",
62 "CMD_SET_GROUP_FREQ",
63 "CMD_GET_THREAD_LOAD",
64 "CMD_GET_GROUP_LOAD",
65 "CMD_SET_GROUP_WINDOW_SIZE",
66 "CMD_SET_GROUP_WINDOW_ROLLOVER",
67 "CMD_SET_PREFERRED_CLUSTER",
68 "CMD_SET_INVALID_INTERVAL",
69 };
70
71 if (cmd >= CMD_ID_MAX) {
72 return "Unknown";
73 }
74
75 return str[cmd];
76 }
77
78 class RTGCtrl::RTGMsg {
79 public:
Build(uint32_t cmd=0,int32_t tgid=0,int64_t data=0)80 static RTGMsg Build(uint32_t cmd = 0, int32_t tgid = 0, int64_t data = 0)
81 {
82 return RTGMsg(cmd, tgid, data);
83 }
84
Cmd(uint32_t var)85 RTGMsg& Cmd(uint32_t var)
86 {
87 this->cmd = var;
88 return *this;
89 }
90
TGid(int32_t var)91 RTGMsg& TGid(int32_t var)
92 {
93 this->tgid = var;
94 return *this;
95 }
96
Data(int64_t var)97 RTGMsg& Data(int64_t var)
98 {
99 this->data = var;
100 return *this;
101 }
102
InSize(uint32_t var)103 RTGMsg& InSize(uint32_t var)
104 {
105 this->in_size = var;
106 return *this;
107 }
108
OutSize(uint32_t var)109 RTGMsg& OutSize(uint32_t var)
110 {
111 this->out_size = var;
112 return *this;
113 }
114
In(void * var)115 RTGMsg& In(void* var)
116 {
117 this->in = var;
118 return *this;
119 }
120
Out(void * var)121 RTGMsg& Out(void* var)
122 {
123 this->out = var;
124 return *this;
125 }
126
Format() const127 std::string Format() const
128 {
129 std::stringstream ss;
130
131 auto formatBuf = [&](const char* head, const char* buf, uint32_t size) {
132 if (!buf || size == 0) {
133 return;
134 }
135
136 ss << head;
137 for (uint32_t i = 0; i < size; ++i) {
138 ss << static_cast<int>(buf[i]) << " ";
139 }
140 };
141
142 ss << "cmd: " << FromatRTGCtrlCmd(cmd);
143 ss << " tgid: " << tgid;
144 ss << " data: " << data;
145
146 ss << std::hex << std::uppercase << std::setfill('0') << std::setw(2);
147
148 formatBuf(" in data: ", static_cast<const char*>(in), in_size);
149 formatBuf(" out data: ", static_cast<const char*>(out), out_size);
150
151 return ss.str();
152 }
153
154 private:
RTGMsg(uint32_t cmd,int32_t tgid,int64_t data)155 RTGMsg(uint32_t cmd, int32_t tgid, int64_t data)
156 : cmd(cmd), tgid(tgid), data(data), in_size(0), out_size(0), in(nullptr), out(nullptr)
157 {
158 }
159
160 uint32_t cmd;
161 int32_t tgid;
162 int64_t data;
163 uint32_t in_size;
164 uint32_t out_size;
165 void* in;
166 void* out;
167 };
168
RTGCtrl()169 RTGCtrl::RTGCtrl()
170 {
171 char filePath[PATH_MAX];
172
173 std::string fileName = "/proc/self/ffrt";
174 if (realpath(fileName.c_str(), filePath) == nullptr) {
175 FFRT_LOGE("Invalid file Path %s", fileName.c_str());
176 return;
177 }
178
179 fd = open(filePath, O_RDWR);
180 if (fd < 0) {
181 FFRT_LOGE("Failed to open RTG, Ret %d", fd);
182 }
183 }
184
~RTGCtrl()185 RTGCtrl::~RTGCtrl()
186 {
187 if (fd < 0) {
188 return;
189 }
190
191 close(fd);
192 }
193
GetThreadGroup()194 int RTGCtrl::GetThreadGroup()
195 {
196 FFRT_TRACE_SCOPE(TRACE_LEVEL1, CREATE_RTG);
197
198 int tgid = -1;
199 RTGMsg msg = RTGMsg::Build(CMD_CREATE_RTG).Out(&tgid).OutSize(sizeof(tgid));
200
201 return RTGIOCtrl(msg) ? tgid : -1;
202 }
203
PutThreadGroup(int tgid)204 bool RTGCtrl::PutThreadGroup(int tgid)
205 {
206 FFRT_TRACE_SCOPE(TRACE_LEVEL1, RELEASE_RTG);
207
208 RTGMsg msg = RTGMsg::Build(CMD_RELEASE_RTG, tgid);
209 return RTGIOCtrl(msg);
210 }
211
JoinThread(int tgid,pid_t tid)212 bool RTGCtrl::JoinThread(int tgid, pid_t tid)
213 {
214 FFRT_TRACE_SCOPE(TRACE_LEVEL1, ADD_RTG_THREAD);
215
216 RTGMsg msg = RTGMsg::Build(CMD_ADD_RTG_THREAD, tgid, tid);
217 return RTGIOCtrl(msg);
218 }
219
RemoveThread(int tgid,pid_t tid)220 bool RTGCtrl::RemoveThread(int tgid, pid_t tid)
221 {
222 FFRT_TRACE_SCOPE(TRACE_LEVEL1, DEL_RTG_THREAD);
223
224 RTGMsg msg = RTGMsg::Build(CMD_DEL_RTG_THREAD, tgid, tid);
225 return RTGIOCtrl(msg);
226 }
227
UpdatePerfUtil(int tgid,int util)228 bool RTGCtrl::UpdatePerfUtil(int tgid, int util)
229 {
230 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_GROUP_UTIL);
231
232 RTGMsg msg = RTGMsg::Build(CMD_SET_GROUP_UTIL, tgid, util);
233 return RTGIOCtrl(msg);
234 }
235
UpdatePerfFreq(int tgid,int64_t freq)236 bool RTGCtrl::UpdatePerfFreq(int tgid, int64_t freq)
237 {
238 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_GROUP_FREQ);
239
240 RTGMsg msg = RTGMsg::Build(CMD_SET_GROUP_FREQ, tgid, freq);
241 return RTGIOCtrl(msg);
242 }
243
UpdateAndGetLoad(int tgid,pid_t tid)244 RTGLoadInfo RTGCtrl::UpdateAndGetLoad(int tgid, pid_t tid)
245 {
246 FFRT_TRACE_SCOPE(TRACE_LEVEL1, GET_THREAD_LOAD);
247
248 RTGLoadInfo info {0};
249 RTGMsg msg = RTGMsg::Build(CMD_GET_THREAD_LOAD, tgid, tid).Out(&info).OutSize(sizeof(info));
250
251 RTGIOCtrl(msg);
252
253 FFRT_LOGI("Get Thread Load %llu Runtime %llu", info.load, info.runtime);
254
255 return info;
256 }
257
UpdateAndGetLoad(int tgid)258 RTGLoadInfo RTGCtrl::UpdateAndGetLoad(int tgid)
259 {
260 FFRT_TRACE_SCOPE(TRACE_LEVEL1, GET_SERIAL_LOAD);
261
262 RTGLoadInfo info {0};
263 RTGMsg msg = RTGMsg::Build(CMD_GET_GROUP_LOAD, tgid).Out(&info).OutSize(sizeof(info));
264
265 RTGIOCtrl(msg);
266
267 FFRT_LOGI("Get Serial Load %llu Runtime %llu", info.load, info.runtime);
268
269 return info;
270 }
271
SetGroupWindowSize(int tgid,uint64_t size)272 bool RTGCtrl::SetGroupWindowSize(int tgid, uint64_t size)
273 {
274 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_GROUP_WINDOW_SIZE);
275
276 RTGMsg msg = RTGMsg::Build(CMD_SET_GROUP_WINDOW_SIZE, tgid, size);
277 return RTGIOCtrl(msg);
278 }
279
SetInvalidInterval(int tgid,uint64_t interval)280 bool RTGCtrl::SetInvalidInterval(int tgid, uint64_t interval)
281 {
282 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_INVALID_INTERVAL);
283
284 RTGMsg msg = RTGMsg::Build(CMD_SET_INVALID_INTERVAL, tgid, interval);
285 return RTGIOCtrl(msg);
286 }
287
Begin(int tgid)288 bool RTGCtrl::Begin(int tgid)
289 {
290 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_GROUP_WINDOW_ROLLOVER_BEGIN);
291
292 RTGMsg msg = RTGMsg::Build(CMD_SET_GROUP_WINDOW_ROLLOVER, tgid, RTG_FRAME_START);
293 return RTGIOCtrl(msg);
294 }
295
End(int tgid)296 bool RTGCtrl::End(int tgid)
297 {
298 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_GROUP_WINDOW_ROLLOVER_END);
299
300 RTGMsg msg = RTGMsg::Build(CMD_SET_GROUP_WINDOW_ROLLOVER, tgid, RTG_FRAME_END);
301 return RTGIOCtrl(msg);
302 }
303
SetPreferredCluster(int tgid,int clusterId)304 bool RTGCtrl::SetPreferredCluster(int tgid, int clusterId)
305 {
306 FFRT_TRACE_SCOPE(TRACE_LEVEL1, SET_PREFERRED_CLUSTER);
307
308 RTGMsg msg = RTGMsg::Build(CMD_SET_PREFERRED_CLUSTER, tgid, clusterId);
309 return RTGIOCtrl(msg);
310 }
311
GetTID()312 pid_t RTGCtrl::GetTID()
313 {
314 return syscall(SYS_gettid);
315 }
316
RTGIOCtrl(RTGMsg & msg)317 bool RTGCtrl::RTGIOCtrl(RTGMsg& msg)
318 {
319 int ret = ioctl(fd, RTG_IPC_CMD, &msg);
320 if (ret < 0) {
321 FFRT_LOGE("RTG IOCtrl Failed Ret:%d, %s\n", ret, msg.Format().c_str());
322 return false;
323 }
324
325 FFRT_LOGD("RTG IOCtrl Success %s\n", msg.Format().c_str());
326
327 return true;
328 }
329 }; // namespace ffrt