1 /*
2 * Copyright (c) 2025 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 #include "sched/stask_scheduler.h"
16 #include "util/ffrt_facade.h"
17
18 namespace {
19 constexpr int TASK_OVERRUN_THRESHOLD = 1000;
20 constexpr int TASK_OVERRUN_ALARM_FREQ = 500;
21 }
22
23 namespace ffrt {
PushTaskGlobal(TaskBase * task,bool rtb)24 bool STaskScheduler::PushTaskGlobal(TaskBase* task, bool rtb)
25 {
26 int taskCount = 0;
27 (void)rtb; // rtb is deprecated here
28 FFRT_COND_DO_ERR((task == nullptr), return false, "task is nullptr");
29
30 int level = task->GetQos();
31 uint64_t gid = task->gid;
32 std::string label = task->GetLabel();
33
34 FFRT_READY_MARKER(gid); // ffrt normal task ready to enqueue
35 {
36 std::lock_guard lg(*GetMutex());
37 // enqueue task and read size under lock-protection
38 que->EnQueue(task);
39 taskCount = que->Size();
40 }
41 // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more.
42 if (taskCount >= TASK_OVERRUN_THRESHOLD && taskCount % TASK_OVERRUN_ALARM_FREQ == 0) {
43 FFRT_SYSEVENT_LOGW("qos [%d], task [%s] entered q, task count [%d] exceeds threshold.",
44 level, label.c_str(), taskCount);
45 }
46
47 return taskCount == 1; // whether it's rising edge
48 }
49
PopTaskHybridProcess()50 TaskBase* STaskScheduler::PopTaskHybridProcess()
51 {
52 TaskBase *task = PopTaskGlobal();
53 if (task == nullptr) {
54 return nullptr;
55 }
56 int wakedWorkerNum = FFRTFacade::GetEUInstance().GetWorkerGroup(qos).executingNum;
57 // when there is only one worker, the global queue is equivalent to the local queue
58 // prevents local queue tasks that cannot be executed due to blocking tasks
59 if (wakedWorkerNum <= 1) {
60 return task;
61 }
62
63 SpmcQueue *queue = GetLocalQueue();
64 int expectedTask = GetGlobalTaskCnt() / wakedWorkerNum - 1;
65 for (int i = 0; i < expectedTask; i++) {
66 if (queue->GetLength() == queue->GetCapacity()) {
67 return task;
68 }
69
70 TaskBase *task2local = PopTaskGlobal();
71 if (task2local == nullptr) {
72 return task;
73 }
74 queue->PushTail(task2local);
75 }
76 if (NeedNotifyWorker(task)) {
77 FFRTFacade::GetEUInstance().NotifyTask<TaskNotifyType::TASK_PICKED>(qos);
78 }
79 return task;
80 }
81 }
82