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 "scheduler.h"
17
18 #include "util/ffrt_facade.h"
19 #include "util/singleton_register.h"
20
21 namespace {
22 constexpr int TASK_OVERRUN_THRESHOLD = 1000;
23 constexpr int TASK_OVERRUN_ALARM_FREQ = 500;
24 }
25
26 namespace ffrt {
27
Instance()28 FFRTScheduler* FFRTScheduler::Instance()
29 {
30 return &SingletonRegister<FFRTScheduler>::Instance();
31 }
32
RegistInsCb(SingleInsCB<FFRTScheduler>::Instance && cb)33 void FFRTScheduler::RegistInsCb(SingleInsCB<FFRTScheduler>::Instance &&cb)
34 {
35 SingletonRegister<FFRTScheduler>::RegistInsCb(std::move(cb));
36 }
37
InsertNode(LinkedList * node,const QoS qos)38 bool FFRTScheduler::InsertNode(LinkedList* node, const QoS qos)
39 {
40 FFRT_COND_DO_ERR((node == nullptr), return false, "Node is NULL");
41
42 int level = qos();
43 FFRT_COND_DO_ERR((level == qos_inherit), return false, "Level incorrect");
44
45 ffrt_executor_task_t* task = reinterpret_cast<ffrt_executor_task_t*>(reinterpret_cast<char*>(node) -
46 offsetof(ffrt_executor_task_t, wq));
47 uintptr_t taskType = task->type;
48
49 auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level);
50 lock->lock();
51 fifoQue[static_cast<unsigned short>(level)]->WakeupNode(node);
52 lock->unlock();
53
54 if (taskType == ffrt_io_task) {
55 FFRTFacade::GetEUInstance().NotifyLocalTaskAdded(qos);
56 return true;
57 }
58
59 FFRTFacade::GetEUInstance().NotifyTaskAdded(qos);
60 return true;
61 }
62
RemoveNode(LinkedList * node,const QoS qos)63 bool FFRTScheduler::RemoveNode(LinkedList* node, const QoS qos)
64 {
65 FFRT_COND_DO_ERR((node == nullptr), return false, "Node is NULL");
66
67 int level = qos();
68 FFRT_COND_DO_ERR((level == qos_inherit), return false, "Level incorrect");
69
70 auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level);
71 lock->lock();
72 if (!node->InList()) {
73 lock->unlock();
74 return false;
75 }
76 fifoQue[static_cast<unsigned short>(level)]->RemoveNode(node);
77 lock->unlock();
78 return true;
79 }
80
WakeupTask(CPUEUTask * task)81 bool FFRTScheduler::WakeupTask(CPUEUTask* task)
82 {
83 FFRT_COND_DO_ERR((task == nullptr), return false, "task is nullptr");
84
85 int qosLevel = task->qos_();
86 if (qosLevel == qos_inherit) {
87 FFRT_LOGE("qos inhert not support wake up task[%lu], type[%d], name[%s]",
88 task->gid, task->type, task->label.c_str());
89 return false;
90 }
91
92 QoS _qos = qosLevel;
93 int level = _qos();
94 uint64_t gid = task->gid;
95 bool notifyWorker = task->notifyWorker_;
96 std::string label = task->label;
97
98 FFRT_READY_MARKER(gid); // ffrt normal task ready to enque
99 auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level);
100 lock->lock();
101 fifoQue[static_cast<unsigned short>(level)]->WakeupTask(task);
102 int taskCount = fifoQue[static_cast<size_t>(level)]->RQSize();
103 lock->unlock();
104
105 // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more.
106 FFRT_LOGD("qos[%d] task[%lu] entered q", level, gid);
107 if (taskCount >= TASK_OVERRUN_THRESHOLD && taskCount % TASK_OVERRUN_ALARM_FREQ == 0) {
108 FFRT_LOGW("qos [%d], task [%s] entered q, task count [%d] exceeds threshold.",
109 level, label.c_str(), taskCount);
110 }
111
112 if (notifyWorker) {
113 FFRTFacade::GetEUInstance().NotifyTaskAdded(_qos);
114 }
115
116 return true;
117 }
118
119 } // namespace ffrt