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 #include <cstdio>
16 #include <cstdlib>
17 #include <cstring>
18 #include <mutex>
19 #include "sched/workgroup_internal.h"
20 #include "dfx/log/ffrt_log_api.h"
21 #include "task_client_adapter.h"
22
23
24 #if (defined(QOS_WORKER_FRAME_RTG) || defined(QOS_FRAME_RTG))
25 constexpr int HWC_UID = 3039;
26 constexpr int ROOT_UID = 0;
27 constexpr int RS_RTG_ID = 10;
28
29 namespace ffrt {
30 static int wgId = -1;
31 static WorkGroup* rsWorkGroup = nullptr;
32 static int wgCount = 0;
33 static std::mutex wgLock;
34
35 #if (defined(QOS_WORKER_FRAME_RTG))
36
WorkgroupInit(struct WorkGroup * wg,uint64_t interval,int rtgId,int qos)37 void WorkgroupInit(struct WorkGroup* wg, uint64_t interval, int rtgId, int qos)
38 {
39 wg->started = false;
40 wg->interval = interval;
41 wg->rtgId = rtgId;
42 wg->qos = qos;
43 wgId = rtgId;
44
45 for (int i = 0; i < MAX_WG_THREADS; i++) {
46 wg->tids[i] = -1;
47 }
48 }
49
FindThreadInWorkGroup(WorkGroup * workGroup,int tid)50 int FindThreadInWorkGroup(WorkGroup *workGroup, int tid)
51 {
52 if (workGroup == nullptr) {
53 FFRT_SYSEVENT_LOGE("[RSWorkGroup] find thread %{public}d in workGroup failed, workGroup is null", tid);
54 return -1;
55 }
56 for (int i = 0;i < MAX_WG_THREADS; i++) {
57 if (workGroup->tids[i] == tid) {
58 return i;
59 }
60 }
61 return -1;
62 }
63
InsertThreadInWorkGroup(WorkGroup * workGroup,int tid)64 bool InsertThreadInWorkGroup(WorkGroup *workGroup, int tid)
65 {
66 if (workGroup == nullptr) {
67 FFRT_SYSEVENT_LOGE("[RSWorkGroup] join thread %{public}d into workGroup failed, workGroup is null", tid);
68 return false;
69 }
70 for (int i = 0; i < MAX_WG_THREADS; i++) {
71 if (workGroup->tids[i] == -1) {
72 workGroup->tids[i] = tid;
73 return true;
74 }
75 }
76 return false;
77 }
78
CreateRSWorkGroup(uint64_t interval,int qos)79 WorkGroup* CreateRSWorkGroup(uint64_t interval, int qos)
80 {
81 IntervalReply rs;
82 rs.rtgId = -1;
83 rs.tid = -1;
84 {
85 std::lock_guard<std::mutex> lck(wgLock);
86 if (rsWorkGroup == nullptr) {
87 CTC_QUERY_INTERVAL(QUERY_RENDER_SERVICE_RENDER, rs);
88 if (rs.rtgId > 0) {
89 rsWorkGroup = new struct WorkGroup();
90 if (rsWorkGroup == nullptr) {
91 FFRT_SYSEVENT_LOGE("[RSWorkGroup] rsWorkGroup malloc failed!");
92 return nullptr;
93 }
94 WorkgroupInit(rsWorkGroup, interval, rs.rtgId, qos);
95 wgCount++;
96 }
97 }
98 }
99 return rsWorkGroup;
100 }
101
LeaveRSWorkGroup(int tid,int qos)102 bool LeaveRSWorkGroup(int tid, int qos)
103 {
104 std::lock_guard<std::mutex> lck(wgLock);
105 if (rsWorkGroup == nullptr || rsWorkGroup->qos != qos) {
106 FFRT_LOGD("[RSWorkGroup] LeaveRSWorkGroup rsWorkGroup is null ,tid:%{public}d", tid);
107 return false;
108 }
109 int existIndex = FindThreadInWorkGroup(rsWorkGroup, tid);
110 if (existIndex != -1) {
111 rsWorkGroup->tids[existIndex] = -1;
112 }
113 FFRT_LOGI("[RSWorkGroup] LeaveRSWorkGroup ,tid: %{public}d, existIndex: %{public}d", tid, existIndex);
114 return true;
115 }
116
JoinRSWorkGroup(int tid,int qos)117 bool JoinRSWorkGroup(int tid, int qos)
118 {
119 std::lock_guard<std::mutex> lck(wgLock);
120 if (rsWorkGroup == nullptr || rsWorkGroup->qos != qos) {
121 FFRT_LOGD("[RSWorkGroup] join thread %{public}d into RSWorkGroup failed; Create RSWorkGroup first",
122 tid);
123 return false;
124 }
125 int existIndex = FindThreadInWorkGroup(rsWorkGroup, tid);
126 if (existIndex == -1) {
127 IntervalReply rs;
128 rs.rtgId = -1;
129 rs.tid = tid;
130 CTC_QUERY_INTERVAL(QUERY_RENDER_SERVICE, rs);
131 if (rs.rtgId > 0) {
132 bool success = InsertThreadInWorkGroup(rsWorkGroup, tid);
133 if (!success) {
134 return false;
135 }
136 }
137 }
138 FFRT_LOGI("[RSWorkGroup] update thread %{public}d success", tid);
139 return true;
140 }
141
DestoryRSWorkGroup(int qos)142 bool DestoryRSWorkGroup(int qos)
143 {
144 std::lock_guard<std::mutex> lck(wgLock);
145 if (rsWorkGroup != nullptr && rsWorkGroup->qos == qos) {
146 delete rsWorkGroup;
147 rsWorkGroup = nullptr;
148 wgId = -1;
149 return true;
150 }
151 return false;
152 }
153 #endif
154
155 #if defined(QOS_FRAME_RTG)
JoinWG(int tid,int qos)156 bool JoinWG(int tid, int qos)
157 {
158 if (wgId < 0) {
159 if (wgCount > 0) {
160 FFRT_SYSEVENT_LOGE("[WorkGroup] interval is unavailable");
161 }
162 return false;
163 }
164 int uid = getuid();
165 if (uid == RS_UID) {
166 return JoinRSWorkGroup(tid, qos);
167 }
168 int addRet = AddThreadToRtgAdapter(tid, wgId, 0);
169 if (addRet == 0) {
170 FFRT_LOGI("[WorkGroup] update thread %{public}d success", tid);
171 } else {
172 FFRT_SYSEVENT_LOGE("[WorkGroup] update thread %{public}d failed, return %{public}d", tid, addRet);
173 }
174 return true;
175 }
176
LeaveWG(int tid,int qos)177 bool LeaveWG(int tid, int qos)
178 {
179 int uid = getuid();
180 if (uid == RS_UID) {
181 return LeaveRSWorkGroup(tid, qos);
182 }
183 return false;
184 }
185
WorkgroupCreate(uint64_t interval,int qos)186 struct WorkGroup* WorkgroupCreate(uint64_t interval, int qos)
187 {
188 int rtgId = -1;
189 int uid = getuid();
190 int num = 0;
191
192 if (uid == RS_UID) {
193 CreateRSWorkGroup(interval);
194 return rsWorkGroup;
195 }
196
197 if (rtgId < 0) {
198 FFRT_SYSEVENT_LOGE("[WorkGroup] create rtg group %d failed", rtgId);
199 return nullptr;
200 }
201 FFRT_LOGI("[WorkGroup] create rtg group %d success", rtgId);
202
203 WorkGroup* wg = nullptr;
204 wg = new struct WorkGroup();
205 if (wg == nullptr) {
206 FFRT_SYSEVENT_LOGE("[WorkGroup] workgroup malloc failed!");
207 return nullptr;
208 }
209 WorkgroupInit(wg, interval, rtgId);
210 {
211 std::lock_guard<std::mutex> lck(wgLock);
212 wgCount++;
213 }
214 return wg;
215 }
216
WorkgroupClear(struct WorkGroup * wg)217 int WorkgroupClear(struct WorkGroup* wg)
218 {
219 if (wg == nullptr) {
220 FFRT_SYSEVENT_LOGE("[WorkGroup] input workgroup is null");
221 return 0;
222 }
223 int uid = getuid();
224 if (uid == RS_UID) {
225 return DestoryRSWorkGroup(wg->qos);
226 }
227 int ret = -1;
228 if (uid != RS_UID) {
229 ret = DestroyRtgGrpAdapter(wg->rtgId);
230 if (ret != 0) {
231 FFRT_SYSEVENT_LOGE("[WorkGroup] destroy rtg group failed");
232 } else {
233 std::lock_guard<std::mutex> lck(wgLock);
234 wgCount--;
235 }
236 }
237 delete wg;
238 wg = nullptr;
239 return ret;
240 }
241
WorkgroupStartInterval(struct WorkGroup * wg)242 void WorkgroupStartInterval(struct WorkGroup* wg)
243 {
244 if (wg == nullptr) {
245 FFRT_SYSEVENT_LOGE("[WorkGroup] input workgroup is null");
246 return;
247 }
248
249 if (wg->started) {
250 FFRT_LOGW("[WorkGroup] already start");
251 return;
252 }
253
254 if (BeginFrameFreqAdapter(0) == 0) {
255 wg->started = true;
256 } else {
257 FFRT_LOGE("[WorkGroup] start rtg(%d) work interval failed", wg->rtgId);
258 }
259 }
260
WorkgroupStopInterval(struct WorkGroup * wg)261 void WorkgroupStopInterval(struct WorkGroup* wg)
262 {
263 if (wg == nullptr) {
264 FFRT_LOGE("[WorkGroup] input workgroup is null");
265 return;
266 }
267
268 if (!wg->started) {
269 FFRT_LOGW("[WorkGroup] already stop");
270 return;
271 }
272
273 int ret = EndFrameFreqAdapter(0);
274 if (ret == 0) {
275 wg->started = false;
276 } else {
277 FFRT_LOGE("[WorkGroup] stop rtg(%d) work interval failed", wg->rtgId);
278 }
279 }
280
WorkgroupJoin(struct WorkGroup * wg,int tid)281 void WorkgroupJoin(struct WorkGroup* wg, int tid)
282 {
283 if (wg == nullptr) {
284 FFRT_LOGE("[WorkGroup] input workgroup is null");
285 return;
286 }
287 int uid = getuid();
288 FFRT_LOGI("[WorkGroup] %s uid = %d rtgid = %d", __func__, uid, wg->rtgId);
289 if (uid == RS_UID) {
290 IntervalReply rs;
291 rs.tid = tid;
292 CTC_QUERY_INTERVAL(QUERY_RENDER_SERVICE, rs);
293 FFRT_LOGI("[WorkGroup] join thread %{public}ld", tid);
294 return;
295 }
296 int addRet = AddThreadToRtgAdapter(tid, wg->rtgId, 0);
297 if (addRet == 0) {
298 FFRT_LOGI("[WorkGroup] join thread %{public}ld success", tid);
299 } else {
300 FFRT_LOGE("[WorkGroup] join fail with %{public}d threads for %{public}d", addRet, tid);
301 }
302 }
303
304 #endif /* QOS_FRAME_RTG */
305 }
306
307 #endif
308