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 if (taskType == ffrt_uv_task || taskType == ffrt_io_task) {
50 FFRT_EXECUTOR_TASK_READY_MARKER(task); // uv/io task ready to enque
51 }
52 auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level);
53 lock->lock();
54 fifoQue[static_cast<unsigned short>(level)]->WakeupNode(node);
55 lock->unlock();
56
57 if (taskType == ffrt_io_task) {
58 FFRTFacade::GetEUInstance().NotifyLocalTaskAdded(qos);
59 return true;
60 }
61
62 FFRTFacade::GetEUInstance().NotifyTaskAdded(qos);
63 return true;
64 }
65
RemoveNode(LinkedList * node,const QoS qos)66 bool FFRTScheduler::RemoveNode(LinkedList* node, const QoS qos)
67 {
68 FFRT_COND_DO_ERR((node == nullptr), return false, "Node is NULL");
69
70 int level = qos();
71 FFRT_COND_DO_ERR((level == qos_inherit), return false, "Level incorrect");
72
73 auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level);
74 lock->lock();
75 if (!node->InList()) {
76 lock->unlock();
77 return false;
78 }
79 fifoQue[static_cast<unsigned short>(level)]->RemoveNode(node);
80 lock->unlock();
81 return true;
82 }
83
WakeupTask(CPUEUTask * task)84 bool FFRTScheduler::WakeupTask(CPUEUTask* task)
85 {
86 FFRT_COND_DO_ERR((task == nullptr), return false, "task is nullptr");
87
88 int qosLevel = task->qos();
89 if (qosLevel == qos_inherit) {
90 FFRT_LOGE("qos inhert not support wake up task[%lu], type[%d], name[%s]",
91 task->gid, task->type, task->label.c_str());
92 return false;
93 }
94
95 QoS _qos = qosLevel;
96 int level = _qos();
97 uint64_t gid = task->gid;
98 bool notifyWorker = task->notifyWorker_;
99 std::string label = task->label;
100
101 FFRT_READY_MARKER(gid); // ffrt normal task ready to enque
102 auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level);
103 lock->lock();
104 fifoQue[static_cast<unsigned short>(level)]->WakeupTask(task);
105 int taskCount = fifoQue[static_cast<size_t>(level)]->RQSize();
106 lock->unlock();
107
108 // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more.
109 FFRT_LOGD("qos[%d] task[%lu] entered q", level, gid);
110 if (taskCount >= TASK_OVERRUN_THRESHOLD && taskCount % TASK_OVERRUN_ALARM_FREQ == 0) {
111 FFRT_LOGW("qos [%d], task [%s] entered q, task count [%d] exceeds threshold.",
112 level, label.c_str(), taskCount);
113 }
114
115 if (notifyWorker) {
116 FFRTFacade::GetEUInstance().NotifyTaskAdded(_qos);
117 }
118
119 return true;
120 }
121
122 } // namespace ffrt