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 "sched/interval.h"
17 #include "util/ffrt_facade.h"
18 #include "ffrt_trace.h"
19
20 namespace ffrt {
Update(uint64_t deadlineUs)21 void Deadline::Update(uint64_t deadlineUs)
22 {
23 if (deadlineUs != ToUs()) {
24 deadlineNs = deadlineUs < 1 ? 1 : deadlineUs * 1000;
25 }
26
27 absDeadlineNs = deadlineNs + AbsNowNs();
28
29 FFRT_LOGI("Deadline %lu Update %lu Abs %lu", deadlineUs, deadlineNs, absDeadlineNs);
30 }
31
AbsNowNs()32 uint64_t Deadline::AbsNowNs()
33 {
34 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch())
35 .count();
36 }
37
PerfCtrl(const QoS & qos)38 PerfCtrl::PerfCtrl(const QoS& qos) : qos(qos)
39 {
40 if (qos == qos_inherit) {
41 FFRT_LOGW("Invalid Thread Group");
42 return;
43 }
44
45 tg = FFRTFacade::GetEUInstance().BindTG(DevType::CPU, this->qos);
46 }
47
~PerfCtrl()48 PerfCtrl::~PerfCtrl()
49 {
50 if (tg) {
51 tg = nullptr;
52 FFRTFacade::GetEUInstance().UnbindTG(DevType::CPU, qos);
53 }
54 }
55
Update(bool force)56 void PerfCtrl::Update(bool force)
57 {
58 if (!force && predUtil == curUtil) {
59 FFRT_LOGW("Predict Util Same as Current Util %lu", predUtil);
60 return;
61 }
62
63 curUtil = predUtil;
64
65 if (tg) {
66 tg->UpdateUitl(curUtil);
67 }
68 }
69
Update(uint64_t deadlineNs,uint64_t load,bool force)70 void PerfCtrl::Update(uint64_t deadlineNs, uint64_t load, bool force)
71 {
72 if (deadlineNs == 0) {
73 deadlineNs = 1;
74 }
75 predUtil = (load << SCHED_CAPACITY_SHIFT) / deadlineNs;
76 if (predUtil > SCHED_MAX_CAPACITY) {
77 FFRT_LOGW("Predict Util %lu Exceeds Max Capacity", predUtil);
78 predUtil = SCHED_MAX_CAPACITY;
79 }
80
81 FFRT_LOGI("Update Load %lu, Deadline %lu, Util %lu\n", load, deadlineNs, predUtil);
82
83 Update(force);
84 }
85
UpdateTotalLoad(uint64_t load)86 void IntervalLoadPredictor::UpdateTotalLoad(uint64_t load)
87 {
88 totalLoad.UpdateLoad(load);
89 }
90
UpdateCPLoad(uint64_t load)91 void IntervalLoadPredictor::UpdateCPLoad(uint64_t load)
92 {
93 if (cpLoadIndex + 1 > cpLoad.size()) {
94 cpLoad.resize(cpLoadIndex + 1);
95 }
96
97 cpLoad[cpLoadIndex++].UpdateLoad(load);
98 }
99
GetTotalLoad()100 uint64_t IntervalLoadPredictor::GetTotalLoad()
101 {
102 return totalLoad.GetPredictLoad();
103 }
104
GetCPLoad()105 uint64_t IntervalLoadPredictor::GetCPLoad()
106 {
107 uint64_t load = cpLoad[cpLoadIndex].GetPredictLoad();
108 if (load == 0) {
109 return 0UL;
110 }
111
112 uint64_t predictLoad = totalLoad.GetPredictLoad();
113 return (predictLoad < load) ? 0 : (predictLoad - load);
114 }
115
DefaultInterval(uint64_t deadlineUs,const QoS & qos)116 DefaultInterval::DefaultInterval(uint64_t deadlineUs, const QoS& qos) : Interval(deadlineUs, qos), lt(*this), ctrl(qos)
117 {
118 ctrl.SetWindowSize(Ddl().ToNs());
119 }
120
~DefaultInterval()121 DefaultInterval::~DefaultInterval()
122 {
123 std::unique_lock lock(mutex);
124 ctrl.Update(1, 0, true);
125 }
126
Begin()127 int DefaultInterval::Begin()
128 {
129 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalBegin);
130 std::unique_lock lock(mutex);
131
132 if (Enabled()) {
133 FFRT_LOGE("interval already begin\n");
134 return -1;
135 }
136
137 if (ctrl.isBusy()) {
138 FFRT_LOGE("qos interval is busy, please retry later\n");
139 return -1;
140 }
141
142 enabled = true;
143
144 lt.Begin();
145
146 ctrl.Update(Ddl().ToNs(), lp.GetTotalLoad(), true);
147 lp.ResetCPIndex();
148
149 return 0;
150 }
151
Update(uint64_t deadlineUs)152 void DefaultInterval::Update(uint64_t deadlineUs)
153 {
154 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalUpdate);
155 std::unique_lock lock(mutex);
156
157 if (!Enabled()) {
158 return;
159 }
160
161 Ddl().Update(deadlineUs);
162 ctrl.SetWindowSize(Ddl().ToNs());
163 }
164
End()165 void DefaultInterval::End()
166 {
167 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalEnd);
168 std::unique_lock lock(mutex);
169
170 if (!Enabled()) {
171 return;
172 }
173
174 enabled = false;
175
176 lp.UpdateTotalLoad(lt.GetLoad());
177
178 lt.End();
179 }
180
CheckPoint()181 void DefaultInterval::CheckPoint()
182 {
183 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalCheckPoint);
184 std::unique_lock lock(mutex);
185
186 if (!Enabled()) {
187 return;
188 }
189
190 ctrl.Update(Ddl().LeftNs(), lp.GetCPLoad());
191 lp.UpdateCPLoad(lt.GetLoad());
192 }
193
Join()194 void DefaultInterval::Join()
195 {
196 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalJoin);
197 std::unique_lock lock(mutex);
198 if (!ctrl.Join()) {
199 FFRT_LOGE("Failed to Join Thread %d", ThreadGroup::GetTID());
200 }
201 }
202
Leave()203 void DefaultInterval::Leave()
204 {
205 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalLeave);
206 std::unique_lock lock(mutex);
207 if (!ctrl.Leave()) {
208 FFRT_LOGE("Failed to Leave Thread %d", ThreadGroup::GetTID());
209 }
210 }
211
UpdateTaskSwitch(TaskSwitchState state)212 void DefaultInterval::UpdateTaskSwitch(TaskSwitchState state)
213 {
214 FFRT_TRACE_SCOPE(TRACE_LEVEL1, IntervalUpdateTaskSwitch);
215 std::unique_lock lock(mutex);
216
217 switch (state) {
218 case TaskSwitchState::BEGIN:
219 ctrl.Update(true);
220 break;
221 case TaskSwitchState::UPDATE:
222 ctrl.Update();
223 break;
224 case TaskSwitchState::END:
225 ctrl.Clear();
226 ctrl.Update(true);
227 break;
228 default:
229 break;
230 }
231
232 lt.Record(state);
233 }
234 } // namespace ffrt
235