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 #ifdef QOS_FRAME_RTG
17 #include "workgroup_internal.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <cstring>
21 #include <mutex>
22 #include "rtg_interface.h"
23 #include "concurrent_task_client.h"
24 #include "dfx/log/ffrt_log_api.h"
25
26 constexpr int HWC_UID = 3039;
27 constexpr int ROOT_UID = 0;
28 constexpr int SYSTEM_UID = 1000;
29 constexpr int RS_RTG_ID = 10;
30
31 using namespace OHOS::ConcurrentTask;
32
33 namespace ffrt {
34 static int wgId = -1;
35 static int wgCount = 0;
36 static std::mutex wgLock;
37
JoinWG(int tid)38 bool JoinWG(int tid)
39 {
40 if (wgId < 0) {
41 if (wgCount > 0) {
42 FFRT_LOGE("[WorkGroup] interval is unavailable");
43 }
44 return false;
45 }
46 int addRet = OHOS::RME::AddThreadToRtg(tid, wgId);
47 if (addRet == 0) {
48 FFRT_LOGI("[WorkGroup] update thread %{public}d success", tid);
49 } else {
50 FFRT_LOGE("[WorkGroup] update thread %{public}d failed, return %{public}d", tid, addRet);
51 }
52 return true;
53 }
54
WorkgroupStartInterval(struct Workgroup * wg)55 void WorkgroupStartInterval(struct Workgroup* wg)
56 {
57 if (wg == nullptr) {
58 FFRT_LOGE("[WorkGroup] input workgroup is null");
59 return;
60 }
61
62 if (wg->started) {
63 FFRT_LOGW("[WorkGroup] already start");
64 return;
65 }
66
67 if (OHOS::RME::BeginFrameFreq(wg->rtgId, 0) == 0) {
68 wg->started = true;
69 } else {
70 FFRT_LOGE("[WorkGroup] start rtg(%{public}d) work interval failed", wg->rtgId);
71 }
72 }
73
WorkgroupStopInterval(struct Workgroup * wg)74 void WorkgroupStopInterval(struct Workgroup* wg)
75 {
76 if (wg == nullptr) {
77 FFRT_LOGE("[WorkGroup] input workgroup is null");
78 return;
79 }
80
81 if (!wg->started) {
82 FFRT_LOGW("[WorkGroup] already stop");
83 return;
84 }
85
86 int ret = OHOS::RME::EndFrameFreq(wg->rtgId);
87 if (ret == 0) {
88 wg->started = false;
89 } else {
90 FFRT_LOGE("[WorkGroup] stop rtg(%{public}d) work interval failed", wg->rtgId);
91 }
92 }
93
WorkgroupInit(struct Workgroup * wg,uint64_t interval,int rtgId)94 static void WorkgroupInit(struct Workgroup* wg, uint64_t interval, int rtgId)
95 {
96 wg->started = false;
97 wg->interval = interval;
98 wg->rtgId = rtgId;
99 wgId = rtgId;
100
101 for (int i = 0; i < MAX_WG_THREADS; i++) {
102 wg->tids[i] = -1;
103 }
104 }
105
WorkgroupCreate(uint64_t interval)106 struct Workgroup* WorkgroupCreate(uint64_t interval)
107 {
108 IntervalReply rs;
109 rs.rtgId = -1;
110 int rtgId = -1;
111 int uid = getuid();
112 int num = 0;
113
114 if (uid == SYSTEM_UID || uid == HWC_UID) {
115 ConcurrentTaskClient::GetInstance().QueryInterval(QUERY_RENDER_SERVICE, rs);
116 rtgId = rs.rtgId;
117 } else if (uid == ROOT_UID) {
118 rtgId = OHOS::RME::CreateNewRtgGrp(num);
119 } else {
120 ConcurrentTaskClient::GetInstance().QueryInterval(QUERY_UI, rs);
121 rtgId = rs.rtgId;
122 }
123
124 if (rtgId < 0) {
125 FFRT_LOGE("[WorkGroup] create rtg group %{public}d failed", rtgId);
126 return nullptr;
127 }
128 FFRT_LOGI("[WorkGroup] create rtg group %{public}d success", rtgId);
129
130 Workgroup* wg = nullptr;
131 wg = new struct Workgroup();
132 if (wg == nullptr) {
133 FFRT_LOGE("[WorkGroup] workgroup malloc failed!");
134 return nullptr;
135 }
136 WorkgroupInit(wg, interval, rtgId);
137 {
138 std::lock_guard<std::mutex> lck(wgLock);
139 wgCount++;
140 }
141 return wg;
142 }
143
WorkgroupJoin(struct Workgroup * wg,int tid)144 void WorkgroupJoin(struct Workgroup* wg, int tid)
145 {
146 if (wg == nullptr) {
147 FFRT_LOGE("[WorkGroup] input workgroup is null");
148 return;
149 }
150 FFRT_LOGI("[WorkGroup] %{public}s uid = %{public}d rtgid = %{public}d", __func__, (int)getuid(), wg->rtgId);
151 int addRet = OHOS::RME::AddThreadToRtg(tid, wg->rtgId);
152 if (addRet == 0) {
153 FFRT_LOGI("[WorkGroup] join thread %{public}ld success", tid);
154 } else {
155 FFRT_LOGE("[WorkGroup] join fail with %{public}d threads for %{public}d", addRet, tid);
156 }
157 }
158
WorkgroupClear(struct Workgroup * wg)159 int WorkgroupClear(struct Workgroup* wg)
160 {
161 if (wg == nullptr) {
162 FFRT_LOGE("[WorkGroup] input workgroup is null");
163 return 0;
164 }
165 int ret = -1;
166 int uid = getuid();
167 if (uid != SYSTEM_UID && uid != HWC_UID) {
168 ret = OHOS::RME::DestroyRtgGrp(wg->rtgId);
169 if (ret != 0) {
170 FFRT_LOGE("[WorkGroup] destroy rtg group failed");
171 } else {
172 FFRT_LOGI("[WorkGroup] destroy rtg group success");
173 {
174 std::lock_guard<std::mutex> lck(wgLock);
175 wgCount--;
176 }
177 }
178 }
179 delete wg;
180 wg = nullptr;
181 return ret;
182 }
183 }
184
185 #endif /* QOS_FRAME_RTG */
186