/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "scheduler.h" #include "util/ffrt_facade.h" #include "util/singleton_register.h" namespace { constexpr int TASK_OVERRUN_THRESHOLD = 1000; constexpr int TASK_OVERRUN_ALARM_FREQ = 500; } namespace ffrt { FFRTScheduler* FFRTScheduler::Instance() { return &SingletonRegister::Instance(); } void FFRTScheduler::RegistInsCb(SingleInsCB::Instance &&cb) { SingletonRegister::RegistInsCb(std::move(cb)); } bool FFRTScheduler::InsertNode(LinkedList* node, const QoS qos) { FFRT_COND_DO_ERR((node == nullptr), return false, "Node is NULL"); int level = qos(); FFRT_COND_DO_ERR((level == qos_inherit), return false, "Level incorrect"); ffrt_executor_task_t* task = reinterpret_cast(reinterpret_cast(node) - offsetof(ffrt_executor_task_t, wq)); uintptr_t taskType = task->type; if (taskType == ffrt_uv_task || taskType == ffrt_io_task) { FFRT_EXECUTOR_TASK_READY_MARKER(task); // uv/io task ready to enque } auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level); lock->lock(); fifoQue[static_cast(level)]->WakeupNode(node); lock->unlock(); if (taskType == ffrt_io_task) { FFRTFacade::GetEUInstance().NotifyLocalTaskAdded(qos); return true; } FFRTFacade::GetEUInstance().NotifyTaskAdded(qos); return true; } bool FFRTScheduler::RemoveNode(LinkedList* node, const QoS qos) { FFRT_COND_DO_ERR((node == nullptr), return false, "Node is NULL"); int level = qos(); FFRT_COND_DO_ERR((level == qos_inherit), return false, "Level incorrect"); auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level); lock->lock(); if (!node->InList()) { lock->unlock(); return false; } fifoQue[static_cast(level)]->RemoveNode(node); lock->unlock(); return true; } bool FFRTScheduler::WakeupTask(CPUEUTask* task) { FFRT_COND_DO_ERR((task == nullptr), return false, "task is nullptr"); int qosLevel = task->qos(); if (qosLevel == qos_inherit) { FFRT_LOGE("qos inhert not support wake up task[%lu], type[%d], name[%s]", task->gid, task->type, task->label.c_str()); return false; } QoS _qos = qosLevel; int level = _qos(); uint64_t gid = task->gid; bool notifyWorker = task->notifyWorker_; std::string label = task->label; FFRT_READY_MARKER(gid); // ffrt normal task ready to enque auto lock = FFRTFacade::GetEUInstance().GetSleepCtl(level); lock->lock(); fifoQue[static_cast(level)]->WakeupTask(task); int taskCount = fifoQue[static_cast(level)]->RQSize(); lock->unlock(); // The ownership of the task belongs to ReadyTaskQueue, and the task cannot be accessed any more. FFRT_LOGD("qos[%d] task[%lu] entered q", level, gid); if (taskCount >= TASK_OVERRUN_THRESHOLD && taskCount % TASK_OVERRUN_ALARM_FREQ == 0) { FFRT_LOGW("qos [%d], task [%s] entered q, task count [%d] exceeds threshold.", level, label.c_str(), taskCount); } if (notifyWorker) { FFRTFacade::GetEUInstance().NotifyTaskAdded(_qos); } return true; } } // namespace ffrt