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