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