feat: support EDF
方案描述: 1、liteos_a调度框架支持EDF调度算法,默认优先调度EDF策略的任务 2、用户态musl_c库适配新增调度算法,同步修改相关接口以支持用户态创建EDF进程与线程 BREAKING CHANGE: support EDF对外变更描述: 以下接口支持SCHED_DEADLINE调度策略: pthread_attr_getschedparam pthread_attr_setschedparam pthread_getschedparam pthread_setschedparam pthread_create sched_getscheduler sched_getparam sched_setparam sched_setscheduler Close:#I6T3P3 Signed-off-by: zhangdengyu <zhangdengyu2@huawei.com> Change-Id: Ic9fe6896fcae42ae4ee7fe5dfb8e858a6ed19740
This commit is contained in:
403
kernel/base/sched/los_deadline.c
Normal file
403
kernel/base/sched/los_deadline.c
Normal file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "los_sched_pri.h"
|
||||
#include "los_task_pri.h"
|
||||
#include "los_process_pri.h"
|
||||
#include "los_hook.h"
|
||||
#include "los_tick_pri.h"
|
||||
#include "los_sys_pri.h"
|
||||
|
||||
STATIC EDFRunqueue g_schedEDF;
|
||||
|
||||
STATIC VOID EDFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB);
|
||||
STATIC VOID EDFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB);
|
||||
STATIC UINT64 EDFWaitTimeGet(LosTaskCB *taskCB);
|
||||
STATIC UINT32 EDFWait(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 ticks);
|
||||
STATIC VOID EDFWake(LosTaskCB *resumedTask);
|
||||
STATIC BOOL EDFSchedParamModify(LosTaskCB *taskCB, const SchedParam *param);
|
||||
STATIC UINT32 EDFSchedParamGet(const LosTaskCB *taskCB, SchedParam *param);
|
||||
STATIC UINT32 EDFDelay(LosTaskCB *runTask, UINT64 waitTime);
|
||||
STATIC VOID EDFYield(LosTaskCB *runTask);
|
||||
STATIC VOID EDFExit(LosTaskCB *taskCB);
|
||||
STATIC UINT32 EDFSuspend(LosTaskCB *taskCB);
|
||||
STATIC UINT32 EDFResume(LosTaskCB *taskCB, BOOL *needSched);
|
||||
STATIC UINT64 EDFTimeSliceGet(const LosTaskCB *taskCB);
|
||||
STATIC VOID EDFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 currTime);
|
||||
STATIC INT32 EDFParamCompare(const SchedPolicy *sp1, const SchedPolicy *sp2);
|
||||
STATIC VOID EDFPriorityInheritance(LosTaskCB *owner, const SchedParam *param);
|
||||
STATIC VOID EDFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param);
|
||||
|
||||
const STATIC SchedOps g_deadlineOps = {
|
||||
.dequeue = EDFDequeue,
|
||||
.enqueue = EDFEnqueue,
|
||||
.waitTimeGet = EDFWaitTimeGet,
|
||||
.wait = EDFWait,
|
||||
.wake = EDFWake,
|
||||
.schedParamModify = EDFSchedParamModify,
|
||||
.schedParamGet = EDFSchedParamGet,
|
||||
.delay = EDFDelay,
|
||||
.yield = EDFYield,
|
||||
.start = EDFDequeue,
|
||||
.exit = EDFExit,
|
||||
.suspend = EDFSuspend,
|
||||
.resume = EDFResume,
|
||||
.deadlineGet = EDFTimeSliceGet,
|
||||
.timeSliceUpdate = EDFTimeSliceUpdate,
|
||||
.schedParamCompare = EDFParamCompare,
|
||||
.priorityInheritance = EDFPriorityInheritance,
|
||||
.priorityRestore = EDFPriorityRestore,
|
||||
};
|
||||
|
||||
STATIC VOID EDFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 currTime)
|
||||
{
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
|
||||
LOS_ASSERT(currTime >= taskCB->startTime);
|
||||
|
||||
if (taskCB->timeSlice <= 0) {
|
||||
taskCB->irqUsedTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
INT32 incTime = (currTime - taskCB->startTime - taskCB->irqUsedTime);
|
||||
LOS_ASSERT(incTime >= 0);
|
||||
|
||||
#ifdef LOSCFG_SCHED_EDF_DEBUG
|
||||
taskCB->schedStat.timeSliceRealTime += incTime;
|
||||
taskCB->schedStat.allRuntime += (currTime - taskCB->startTime);
|
||||
#endif
|
||||
|
||||
taskCB->timeSlice -= incTime;
|
||||
taskCB->irqUsedTime = 0;
|
||||
taskCB->startTime = currTime;
|
||||
|
||||
if ((sched->finishTime > currTime) && (taskCB->timeSlice > 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rq->schedFlag |= INT_PEND_RESCH;
|
||||
if (sched->finishTime <= currTime) {
|
||||
#ifdef LOSCFG_SCHED_EDF_DEBUG
|
||||
EDFDebugRecord((UINTPTR *)taskCB, sched->finishTime);
|
||||
#endif
|
||||
|
||||
taskCB->timeSlice = 0;
|
||||
PrintExcInfo("EDF task %u is timeout, runTime: %d us period: %llu us\n", taskCB->taskID,
|
||||
(INT32)OS_SYS_CYCLE_TO_US((UINT64)sched->runTime), OS_SYS_CYCLE_TO_US(sched->period));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC UINT64 EDFTimeSliceGet(const LosTaskCB *taskCB)
|
||||
{
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
UINT64 endTime = taskCB->startTime + taskCB->timeSlice;
|
||||
return (endTime > sched->finishTime) ? sched->finishTime : endTime;
|
||||
}
|
||||
|
||||
STATIC VOID DeadlineQueueInsert(EDFRunqueue *rq, LosTaskCB *taskCB)
|
||||
{
|
||||
LOS_DL_LIST *root = &rq->root;
|
||||
if (LOS_ListEmpty(root)) {
|
||||
LOS_ListTailInsert(root, &taskCB->pendList);
|
||||
return;
|
||||
}
|
||||
|
||||
LOS_DL_LIST *list = root->pstNext;
|
||||
do {
|
||||
LosTaskCB *readyTask = LOS_DL_LIST_ENTRY(list, LosTaskCB, pendList);
|
||||
if (EDFParamCompare(&readyTask->sp, &taskCB->sp) > 0) {
|
||||
LOS_ListHeadInsert(list, &taskCB->pendList);
|
||||
return;
|
||||
}
|
||||
list = list->pstNext;
|
||||
} while (list != root);
|
||||
|
||||
LOS_ListHeadInsert(list, &taskCB->pendList);
|
||||
}
|
||||
|
||||
STATIC VOID EDFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB)
|
||||
{
|
||||
LOS_ASSERT(!(taskCB->taskStatus & OS_TASK_STATUS_READY));
|
||||
|
||||
EDFRunqueue *erq = rq->edfRunqueue;
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
if (taskCB->timeSlice <= 0) {
|
||||
#ifdef LOSCFG_SCHED_EDF_DEBUG
|
||||
UINT64 oldFinish = sched->finishTime;
|
||||
#endif
|
||||
UINT64 currTime = OsGetCurrSchedTimeCycle();
|
||||
if (sched->flags == EDF_INIT) {
|
||||
sched->finishTime = currTime;
|
||||
} else if (sched->flags != EDF_NEXT_PERIOD) {
|
||||
/* The start time of the next period */
|
||||
sched->finishTime = (sched->finishTime - sched->deadline) + sched->period;
|
||||
}
|
||||
|
||||
/* Calculate the start time of the next period */
|
||||
while (1) {
|
||||
/* The deadline of the next period */
|
||||
UINT64 finishTime = sched->finishTime + sched->deadline;
|
||||
if ((finishTime <= currTime) || ((sched->finishTime + sched->runTime) > finishTime)) {
|
||||
/* This period cannot meet the minimum running time, so it is migrated to the next period */
|
||||
sched->finishTime += sched->period;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sched->finishTime > currTime) {
|
||||
/* Wait for the next period to start */
|
||||
LOS_ListTailInsert(&erq->waitList, &taskCB->pendList);
|
||||
taskCB->waitTime = OS_SCHED_MAX_RESPONSE_TIME;
|
||||
if (!OsTaskIsRunning(taskCB)) {
|
||||
OsSchedTimeoutQueueAdd(taskCB, sched->finishTime);
|
||||
}
|
||||
#ifdef LOSCFG_SCHED_EDF_DEBUG
|
||||
if (oldFinish != sched->finishTime) {
|
||||
EDFDebugRecord((UINTPTR *)taskCB, oldFinish);
|
||||
taskCB->schedStat.allRuntime = 0;
|
||||
taskCB->schedStat.timeSliceRealTime = 0;
|
||||
taskCB->schedStat.pendTime = 0;
|
||||
}
|
||||
#endif
|
||||
taskCB->taskStatus |= OS_TASK_STATUS_PEND_TIME;
|
||||
sched->flags = EDF_NEXT_PERIOD;
|
||||
return;
|
||||
}
|
||||
|
||||
sched->finishTime += sched->deadline;
|
||||
taskCB->timeSlice = sched->runTime;
|
||||
sched->flags = EDF_UNUSED;
|
||||
}
|
||||
|
||||
DeadlineQueueInsert(erq, taskCB);
|
||||
taskCB->taskStatus &= ~(OS_TASK_STATUS_BLOCKED | OS_TASK_STATUS_TIMEOUT);
|
||||
taskCB->taskStatus |= OS_TASK_STATUS_READY;
|
||||
}
|
||||
|
||||
STATIC VOID EDFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB)
|
||||
{
|
||||
(VOID)rq;
|
||||
LOS_ListDelete(&taskCB->pendList);
|
||||
taskCB->taskStatus &= ~OS_TASK_STATUS_READY;
|
||||
}
|
||||
|
||||
STATIC VOID EDFExit(LosTaskCB *taskCB)
|
||||
{
|
||||
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
|
||||
EDFDequeue(OsSchedRunqueue(), taskCB);
|
||||
} else if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) {
|
||||
LOS_ListDelete(&taskCB->pendList);
|
||||
taskCB->taskStatus &= ~OS_TASK_STATUS_PENDING;
|
||||
}
|
||||
if (taskCB->taskStatus & (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME)) {
|
||||
OsSchedTimeoutQueueDelete(taskCB);
|
||||
taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC VOID EDFYield(LosTaskCB *runTask)
|
||||
{
|
||||
SchedRunqueue *rq = OsSchedRunqueue();
|
||||
runTask->timeSlice = 0;
|
||||
|
||||
runTask->startTime = OsGetCurrSchedTimeCycle();
|
||||
EDFEnqueue(rq, runTask);
|
||||
OsSchedResched();
|
||||
}
|
||||
|
||||
STATIC UINT32 EDFDelay(LosTaskCB *runTask, UINT64 waitTime)
|
||||
{
|
||||
runTask->taskStatus |= OS_TASK_STATUS_DELAY;
|
||||
runTask->waitTime = waitTime;
|
||||
OsSchedResched();
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT64 EDFWaitTimeGet(LosTaskCB *taskCB)
|
||||
{
|
||||
const SchedEDF *sched = (const SchedEDF *)&taskCB->sp;
|
||||
if (sched->flags != EDF_WAIT_FOREVER) {
|
||||
taskCB->waitTime += taskCB->startTime;
|
||||
}
|
||||
return (taskCB->waitTime >= sched->finishTime) ? sched->finishTime : taskCB->waitTime;
|
||||
}
|
||||
|
||||
STATIC UINT32 EDFWait(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 ticks)
|
||||
{
|
||||
SchedEDF *sched = (SchedEDF *)&runTask->sp;
|
||||
runTask->taskStatus |= (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME);
|
||||
LOS_ListTailInsert(list, &runTask->pendList);
|
||||
|
||||
if (ticks != LOS_WAIT_FOREVER) {
|
||||
runTask->waitTime = OS_SCHED_TICK_TO_CYCLE(ticks);
|
||||
} else {
|
||||
sched->flags = EDF_WAIT_FOREVER;
|
||||
runTask->waitTime = OS_SCHED_MAX_RESPONSE_TIME;
|
||||
}
|
||||
|
||||
if (OsPreemptableInSched()) {
|
||||
OsSchedResched();
|
||||
if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
|
||||
runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
|
||||
return LOS_ERRNO_TSK_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC VOID EDFWake(LosTaskCB *resumedTask)
|
||||
{
|
||||
LOS_ListDelete(&resumedTask->pendList);
|
||||
resumedTask->taskStatus &= ~OS_TASK_STATUS_PENDING;
|
||||
|
||||
if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) {
|
||||
OsSchedTimeoutQueueDelete(resumedTask);
|
||||
resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
|
||||
}
|
||||
|
||||
if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) {
|
||||
#ifdef LOSCFG_SCHED_EDF_DEBUG
|
||||
resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->startTime;
|
||||
resumedTask->schedStat.pendCount++;
|
||||
#endif
|
||||
EDFEnqueue(OsSchedRunqueue(), resumedTask);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC BOOL EDFSchedParamModify(LosTaskCB *taskCB, const SchedParam *param)
|
||||
{
|
||||
SchedRunqueue *rq = OsSchedRunqueue();
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
|
||||
taskCB->timeSlice = 0;
|
||||
sched->runTime = (INT32)OS_SYS_US_TO_CYCLE(param->runTimeUs);
|
||||
sched->period = OS_SYS_US_TO_CYCLE(param->periodUs);
|
||||
|
||||
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
|
||||
EDFDequeue(rq, taskCB);
|
||||
sched->deadline = OS_SYS_US_TO_CYCLE(param->deadlineUs);
|
||||
EDFEnqueue(rq, taskCB);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
sched->deadline = OS_SYS_US_TO_CYCLE(param->deadlineUs);
|
||||
if (taskCB->taskStatus & OS_TASK_STATUS_INIT) {
|
||||
EDFEnqueue(rq, taskCB);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STATIC UINT32 EDFSchedParamGet(const LosTaskCB *taskCB, SchedParam *param)
|
||||
{
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
param->policy = sched->policy;
|
||||
param->runTimeUs = (INT32)OS_SYS_CYCLE_TO_US((UINT64)sched->runTime);
|
||||
param->deadlineUs = OS_SYS_CYCLE_TO_US(sched->deadline);
|
||||
param->periodUs = OS_SYS_CYCLE_TO_US(sched->period);
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT32 EDFSuspend(LosTaskCB *taskCB)
|
||||
{
|
||||
return LOS_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
STATIC UINT32 EDFResume(LosTaskCB *taskCB, BOOL *needSched)
|
||||
{
|
||||
return LOS_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
STATIC INT32 EDFParamCompare(const SchedPolicy *sp1, const SchedPolicy *sp2)
|
||||
{
|
||||
const SchedEDF *param1 = (const SchedEDF *)sp1;
|
||||
const SchedEDF *param2 = (const SchedEDF *)sp2;
|
||||
|
||||
return (INT32)(param1->finishTime - param2->finishTime);
|
||||
}
|
||||
|
||||
STATIC VOID EDFPriorityInheritance(LosTaskCB *owner, const SchedParam *param)
|
||||
{
|
||||
(VOID)owner;
|
||||
(VOID)param;
|
||||
}
|
||||
|
||||
STATIC VOID EDFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const SchedParam *param)
|
||||
{
|
||||
(VOID)owner;
|
||||
(VOID)list;
|
||||
(VOID)param;
|
||||
}
|
||||
|
||||
UINT32 EDFTaskSchedParamInit(LosTaskCB *taskCB, UINT16 policy,
|
||||
const SchedParam *parentParam,
|
||||
const LosSchedParam *param)
|
||||
{
|
||||
(VOID)parentParam;
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
sched->flags = EDF_INIT;
|
||||
sched->policy = policy;
|
||||
sched->runTime = (INT32)OS_SYS_US_TO_CYCLE((UINT64)param->runTimeUs);
|
||||
sched->deadline = OS_SYS_US_TO_CYCLE(param->deadlineUs);
|
||||
sched->period = OS_SYS_US_TO_CYCLE(param->periodUs);
|
||||
sched->finishTime = 0;
|
||||
taskCB->timeSlice = 0;
|
||||
taskCB->ops = &g_deadlineOps;
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
VOID EDFProcessDefaultSchedParamGet(SchedParam *param)
|
||||
{
|
||||
param->runTimeUs = OS_SCHED_EDF_MIN_RUNTIME;
|
||||
param->deadlineUs = OS_SCHED_EDF_MAX_DEADLINE;
|
||||
param->periodUs = param->deadlineUs;
|
||||
}
|
||||
|
||||
VOID EDFSchedPolicyInit(SchedRunqueue *rq)
|
||||
{
|
||||
if (ArchCurrCpuid() > 0) {
|
||||
rq->edfRunqueue = &g_schedEDF;
|
||||
return;
|
||||
}
|
||||
|
||||
EDFRunqueue *erq = &g_schedEDF;
|
||||
erq->period = OS_SCHED_MAX_RESPONSE_TIME;
|
||||
LOS_ListInit(&erq->root);
|
||||
LOS_ListInit(&erq->waitList);
|
||||
rq->edfRunqueue = erq;
|
||||
}
|
||||
@@ -48,6 +48,7 @@ STATIC VOID IdlePriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const
|
||||
const STATIC SchedOps g_idleOps = {
|
||||
.dequeue = IdleDequeue,
|
||||
.enqueue = IdleEnqueue,
|
||||
.waitTimeGet = NULL,
|
||||
.wait = IdleWait,
|
||||
.wake = IdleWake,
|
||||
.schedParamModify = NULL,
|
||||
|
||||
@@ -47,6 +47,7 @@ STATIC HPFRunqueue g_schedHPF;
|
||||
|
||||
STATIC VOID HPFDequeue(SchedRunqueue *rq, LosTaskCB *taskCB);
|
||||
STATIC VOID HPFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB);
|
||||
STATIC UINT64 HPFWaitTimeGet(LosTaskCB *taskCB);
|
||||
STATIC UINT32 HPFWait(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 ticks);
|
||||
STATIC VOID HPFWake(LosTaskCB *resumedTask);
|
||||
STATIC BOOL HPFSchedParamModify(LosTaskCB *taskCB, const SchedParam *param);
|
||||
@@ -66,6 +67,7 @@ STATIC VOID HPFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const
|
||||
const STATIC SchedOps g_priorityOps = {
|
||||
.dequeue = HPFDequeue,
|
||||
.enqueue = HPFEnqueue,
|
||||
.waitTimeGet = HPFWaitTimeGet,
|
||||
.wait = HPFWait,
|
||||
.wake = HPFWake,
|
||||
.schedParamModify = HPFSchedParamModify,
|
||||
@@ -94,7 +96,7 @@ STATIC VOID HPFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 curr
|
||||
|
||||
if (sched->policy == LOS_SCHED_RR) {
|
||||
taskCB->timeSlice -= incTime;
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
taskCB->schedStat.timeSliceRealTime += incTime;
|
||||
#endif
|
||||
}
|
||||
@@ -107,7 +109,7 @@ STATIC VOID HPFTimeSliceUpdate(SchedRunqueue *rq, LosTaskCB *taskCB, UINT64 curr
|
||||
rq->schedFlag |= INT_PEND_RESCH;
|
||||
}
|
||||
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
taskCB->schedStat.allRuntime += incTime;
|
||||
#endif
|
||||
}
|
||||
@@ -215,7 +217,7 @@ STATIC INLINE VOID PriQueInsert(HPFRunqueue *rq, LosTaskCB *taskCB)
|
||||
sched->initTimeSlice = TimeSliceCalculate(rq, sched->basePrio, sched->priority);
|
||||
taskCB->timeSlice = sched->initTimeSlice;
|
||||
PriQueTailInsert(rq, sched->basePrio, &taskCB->pendList, sched->priority);
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
taskCB->schedStat.timeSliceTime = taskCB->schedStat.timeSliceRealTime;
|
||||
taskCB->schedStat.timeSliceCount++;
|
||||
#endif
|
||||
@@ -244,7 +246,7 @@ STATIC INLINE VOID PriQueInsert(HPFRunqueue *rq, LosTaskCB *taskCB)
|
||||
|
||||
STATIC VOID HPFEnqueue(SchedRunqueue *rq, LosTaskCB *taskCB)
|
||||
{
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
if (!(taskCB->taskStatus & OS_TASK_STATUS_RUNNING)) {
|
||||
taskCB->startTime = OsGetCurrSchedTimeCycle();
|
||||
}
|
||||
@@ -301,6 +303,12 @@ STATIC UINT32 HPFDelay(LosTaskCB *runTask, UINT64 waitTime)
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT64 HPFWaitTimeGet(LosTaskCB *taskCB)
|
||||
{
|
||||
taskCB->waitTime += taskCB->startTime;
|
||||
return taskCB->waitTime;
|
||||
}
|
||||
|
||||
STATIC UINT32 HPFWait(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 ticks)
|
||||
{
|
||||
runTask->taskStatus |= OS_TASK_STATUS_PENDING;
|
||||
@@ -333,7 +341,7 @@ STATIC VOID HPFWake(LosTaskCB *resumedTask)
|
||||
}
|
||||
|
||||
if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPENDED)) {
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
resumedTask->schedStat.pendTime += OsGetCurrSchedTimeCycle() - resumedTask->startTime;
|
||||
resumedTask->schedStat.pendCount++;
|
||||
#endif
|
||||
@@ -508,13 +516,13 @@ STATIC VOID HPFPriorityRestore(LosTaskCB *owner, const LOS_DL_LIST *list, const
|
||||
|
||||
VOID HPFTaskSchedParamInit(LosTaskCB *taskCB, UINT16 policy,
|
||||
const SchedParam *parentParam,
|
||||
const TSK_INIT_PARAM_S *param)
|
||||
const LosSchedParam *param)
|
||||
{
|
||||
SchedHPF *sched = (SchedHPF *)&taskCB->sp;
|
||||
|
||||
sched->policy = policy;
|
||||
if (param != NULL) {
|
||||
sched->priority = param->usTaskPrio;
|
||||
sched->priority = param->priority;
|
||||
} else {
|
||||
sched->priority = parentParam->priority;
|
||||
}
|
||||
|
||||
@@ -102,15 +102,26 @@ VOID OsSchedExpireTimeUpdate(VOID)
|
||||
|
||||
STATIC INLINE VOID SchedTimeoutTaskWake(SchedRunqueue *rq, UINT64 currTime, LosTaskCB *taskCB, BOOL *needSched)
|
||||
{
|
||||
#ifndef LOSCFG_SCHED_DEBUG
|
||||
(VOID)currTime;
|
||||
#endif
|
||||
|
||||
LOS_SpinLock(&g_taskSpin);
|
||||
if (OsSchedPolicyIsEDF(taskCB)) {
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
if (sched->finishTime <= currTime) {
|
||||
if (taskCB->timeSlice >= 0) {
|
||||
PrintExcInfo("EDF task: %u name: %s is timeout, timeout for %llu us.\n",
|
||||
taskCB->taskID, taskCB->taskName, OS_SYS_CYCLE_TO_US(currTime - sched->finishTime));
|
||||
}
|
||||
taskCB->timeSlice = 0;
|
||||
}
|
||||
if (sched->flags == EDF_WAIT_FOREVER) {
|
||||
taskCB->taskStatus &= ~OS_TASK_STATUS_PEND_TIME;
|
||||
sched->flags = EDF_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
UINT16 tempStatus = taskCB->taskStatus;
|
||||
if (tempStatus & (OS_TASK_STATUS_PENDING | OS_TASK_STATUS_DELAY)) {
|
||||
if (tempStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
|
||||
taskCB->taskStatus &= ~(OS_TASK_STATUS_PENDING | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY);
|
||||
if (tempStatus & OS_TASK_STATUS_PENDING) {
|
||||
if (tempStatus & OS_TASK_STATUS_PEND_TIME) {
|
||||
taskCB->taskStatus |= OS_TASK_STATUS_TIMEOUT;
|
||||
LOS_ListDelete(&taskCB->pendList);
|
||||
taskCB->taskMux = NULL;
|
||||
@@ -118,7 +129,7 @@ STATIC INLINE VOID SchedTimeoutTaskWake(SchedRunqueue *rq, UINT64 currTime, LosT
|
||||
}
|
||||
|
||||
if (!(tempStatus & OS_TASK_STATUS_SUSPENDED)) {
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
taskCB->schedStat.pendTime += currTime - taskCB->startTime;
|
||||
taskCB->schedStat.pendCount++;
|
||||
#endif
|
||||
@@ -212,8 +223,10 @@ VOID OsSchedRunqueueIdleInit(LosTaskCB *idleTask)
|
||||
|
||||
UINT32 OsSchedInit(VOID)
|
||||
{
|
||||
for (UINT16 cpuId = 0; cpuId < LOSCFG_KERNEL_CORE_NUM; cpuId++) {
|
||||
HPFSchedPolicyInit(OsSchedRunqueueByID(cpuId));
|
||||
for (UINT16 cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {
|
||||
SchedRunqueue *rq = OsSchedRunqueueByID(cpuid);
|
||||
EDFSchedPolicyInit(rq);
|
||||
HPFSchedPolicyInit(rq);
|
||||
}
|
||||
|
||||
#ifdef LOSCFG_SCHED_TICK_DEBUG
|
||||
@@ -247,13 +260,15 @@ INT32 OsSchedParamCompare(const LosTaskCB *task1, const LosTaskCB *task2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 OsSchedParamInit(LosTaskCB *taskCB, UINT16 policy, const SchedParam *parentParam, const TSK_INIT_PARAM_S *param)
|
||||
UINT32 OsSchedParamInit(LosTaskCB *taskCB, UINT16 policy, const SchedParam *parentParam, const LosSchedParam *param)
|
||||
{
|
||||
switch (policy) {
|
||||
case LOS_SCHED_FIFO:
|
||||
case LOS_SCHED_RR:
|
||||
HPFTaskSchedParamInit(taskCB, policy, parentParam, param);
|
||||
break;
|
||||
case LOS_SCHED_DEADLINE:
|
||||
return EDFTaskSchedParamInit(taskCB, policy, parentParam, param);
|
||||
case LOS_SCHED_IDLE:
|
||||
IdleTaskSchedParamInit(taskCB);
|
||||
break;
|
||||
@@ -271,6 +286,9 @@ VOID OsSchedProcessDefaultSchedParamGet(UINT16 policy, SchedParam *param)
|
||||
case LOS_SCHED_RR:
|
||||
HPFProcessDefaultSchedParamGet(param);
|
||||
break;
|
||||
case LOS_SCHED_DEADLINE:
|
||||
EDFProcessDefaultSchedParamGet(param);
|
||||
break;
|
||||
case LOS_SCHED_IDLE:
|
||||
default:
|
||||
PRINT_ERR("Invalid process-level scheduling policy, %u\n", policy);
|
||||
@@ -281,12 +299,19 @@ VOID OsSchedProcessDefaultSchedParamGet(UINT16 policy, SchedParam *param)
|
||||
|
||||
STATIC LosTaskCB *TopTaskGet(SchedRunqueue *rq)
|
||||
{
|
||||
LosTaskCB *newTask = HPFRunqueueTopTaskGet(rq->hpfRunqueue);
|
||||
|
||||
if (newTask == NULL) {
|
||||
newTask = rq->idleTask;
|
||||
LosTaskCB *newTask = EDFRunqueueTopTaskGet(rq->edfRunqueue);
|
||||
if (newTask != NULL) {
|
||||
goto FIND;
|
||||
}
|
||||
|
||||
newTask = HPFRunqueueTopTaskGet(rq->hpfRunqueue);
|
||||
if (newTask != NULL) {
|
||||
goto FIND;
|
||||
}
|
||||
|
||||
newTask = rq->idleTask;
|
||||
|
||||
FIND:
|
||||
newTask->ops->start(rq, newTask);
|
||||
return newTask;
|
||||
}
|
||||
@@ -387,7 +412,7 @@ STATIC VOID SchedTaskSwitch(SchedRunqueue *rq, LosTaskCB *runTask, LosTaskCB *ne
|
||||
OsCpupCycleEndStart(runTask, newTask);
|
||||
#endif
|
||||
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
UINT64 waitStartTime = newTask->startTime;
|
||||
#endif
|
||||
if (runTask->taskStatus & OS_TASK_STATUS_READY) {
|
||||
@@ -400,14 +425,14 @@ STATIC VOID SchedTaskSwitch(SchedRunqueue *rq, LosTaskCB *runTask, LosTaskCB *ne
|
||||
runTask->ops->timeSliceUpdate(rq, runTask, newTask->startTime);
|
||||
|
||||
if (runTask->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) {
|
||||
OsSchedTimeoutQueueAdd(runTask, runTask->startTime + runTask->waitTime);
|
||||
OsSchedTimeoutQueueAdd(runTask, runTask->ops->waitTimeGet(runTask));
|
||||
}
|
||||
}
|
||||
|
||||
UINT64 deadline = newTask->ops->deadlineGet(newTask);
|
||||
SchedNextExpireTimeSet(newTask->taskID, deadline, runTask->taskID);
|
||||
|
||||
#ifdef LOSCFG_SCHED_DEBUG
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
newTask->schedStat.waitSchedTime += newTask->startTime - waitStartTime;
|
||||
newTask->schedStat.waitSchedCount++;
|
||||
runTask->schedStat.runTime = runTask->schedStat.allRuntime;
|
||||
|
||||
@@ -99,6 +99,7 @@ UINT32 OsShellShowTickResponse(VOID)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LOSCFG_SCHED_HPF_DEBUG
|
||||
STATIC VOID SchedDataGet(const LosTaskCB *taskCB, UINT64 *runTime, UINT64 *timeSlice,
|
||||
UINT64 *pendTime, UINT64 *schedWait)
|
||||
{
|
||||
@@ -128,6 +129,7 @@ UINT32 OsShellShowSchedStatistics(VOID)
|
||||
UINT32 taskLinkNum[LOSCFG_KERNEL_CORE_NUM];
|
||||
UINT32 intSave;
|
||||
LosTaskCB task;
|
||||
SchedEDF *sched = NULL;
|
||||
|
||||
SCHEDULER_LOCK(intSave);
|
||||
for (UINT16 cpu = 0; cpu < LOSCFG_KERNEL_CORE_NUM; cpu++) {
|
||||
@@ -150,6 +152,12 @@ UINT32 OsShellShowSchedStatistics(VOID)
|
||||
continue;
|
||||
}
|
||||
|
||||
sched = (SchedEDF *)&taskCB->sp;
|
||||
if (sched->policy == LOS_SCHED_DEADLINE) {
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
continue;
|
||||
}
|
||||
|
||||
(VOID)memcpy_s(&task, sizeof(LosTaskCB), taskCB, sizeof(LosTaskCB));
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
|
||||
@@ -170,3 +178,168 @@ UINT32 OsShellShowSchedStatistics(VOID)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LOSCFG_SCHED_EDF_DEBUG
|
||||
#define EDF_DEBUG_NODE 20
|
||||
typedef struct {
|
||||
UINT32 tid;
|
||||
INT32 runTimeUs;
|
||||
UINT64 deadlineUs;
|
||||
UINT64 periodUs;
|
||||
UINT64 startTime;
|
||||
UINT64 finishTime;
|
||||
UINT64 nextfinishTime;
|
||||
UINT64 timeSliceUnused;
|
||||
UINT64 timeSliceRealTime;
|
||||
UINT64 allRuntime;
|
||||
UINT64 pendTime;
|
||||
} EDFDebug;
|
||||
|
||||
STATIC EDFDebug g_edfNode[EDF_DEBUG_NODE];
|
||||
STATIC INT32 g_edfNodePointer = 0;
|
||||
|
||||
VOID EDFDebugRecord(UINTPTR *task, UINT64 oldFinish)
|
||||
{
|
||||
LosTaskCB *taskCB = (LosTaskCB *)task;
|
||||
SchedEDF *sched = (SchedEDF *)&taskCB->sp;
|
||||
SchedParam param;
|
||||
|
||||
// when print edf info, will stop record
|
||||
if (g_edfNodePointer == (EDF_DEBUG_NODE + 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
taskCB->ops->schedParamGet(taskCB, ¶m);
|
||||
g_edfNode[g_edfNodePointer].tid = taskCB->taskID;
|
||||
g_edfNode[g_edfNodePointer].runTimeUs =param.runTimeUs;
|
||||
g_edfNode[g_edfNodePointer].deadlineUs =param.deadlineUs;
|
||||
g_edfNode[g_edfNodePointer].periodUs =param.periodUs;
|
||||
g_edfNode[g_edfNodePointer].startTime = taskCB->startTime;
|
||||
if (taskCB->timeSlice <= 0) {
|
||||
taskCB->irqUsedTime = 0;
|
||||
g_edfNode[g_edfNodePointer].timeSliceUnused = 0;
|
||||
} else {
|
||||
g_edfNode[g_edfNodePointer].timeSliceUnused = taskCB->timeSlice;
|
||||
}
|
||||
g_edfNode[g_edfNodePointer].finishTime = oldFinish;
|
||||
g_edfNode[g_edfNodePointer].nextfinishTime = sched->finishTime;
|
||||
g_edfNode[g_edfNodePointer].timeSliceRealTime = taskCB->schedStat.timeSliceRealTime;
|
||||
g_edfNode[g_edfNodePointer].allRuntime = taskCB->schedStat.allRuntime;
|
||||
g_edfNode[g_edfNodePointer].pendTime = taskCB->schedStat.pendTime;
|
||||
|
||||
g_edfNodePointer++;
|
||||
if (g_edfNodePointer == EDF_DEBUG_NODE) {
|
||||
g_edfNodePointer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC VOID EDFInfoPrint(int idx)
|
||||
{
|
||||
INT32 runTimeUs;
|
||||
UINT64 deadlineUs;
|
||||
UINT64 periodUs;
|
||||
UINT64 startTime;
|
||||
UINT64 timeSlice;
|
||||
UINT64 finishTime;
|
||||
UINT64 nextfinishTime;
|
||||
UINT64 pendTime;
|
||||
UINT64 allRuntime;
|
||||
UINT64 timeSliceRealTime;
|
||||
CHAR *status = NULL;
|
||||
|
||||
startTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].startTime);
|
||||
timeSlice = OS_SYS_CYCLE_TO_US(g_edfNode[idx].timeSliceUnused);
|
||||
finishTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].finishTime);
|
||||
nextfinishTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].nextfinishTime);
|
||||
pendTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].pendTime);
|
||||
allRuntime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].allRuntime);
|
||||
timeSliceRealTime = OS_SYS_CYCLE_TO_US(g_edfNode[idx].timeSliceRealTime);
|
||||
runTimeUs = g_edfNode[idx].runTimeUs;
|
||||
deadlineUs = g_edfNode[idx].deadlineUs;
|
||||
periodUs = g_edfNode[idx].periodUs;
|
||||
|
||||
if (timeSlice > 0) {
|
||||
status = "TIMEOUT";
|
||||
} else if (nextfinishTime == finishTime) {
|
||||
status = "NEXT PERIOD";
|
||||
} else {
|
||||
status = "WAIT RUN";
|
||||
}
|
||||
|
||||
PRINTK("%4u%9d%9llu%9llu%12llu%12llu%12llu%9llu%9llu%9llu%9llu %-12s\n",
|
||||
g_edfNode[idx].tid, runTimeUs, deadlineUs, periodUs,
|
||||
startTime, finishTime, nextfinishTime, allRuntime, timeSliceRealTime,
|
||||
timeSlice, pendTime, status);
|
||||
}
|
||||
|
||||
VOID OsEDFDebugPrint(VOID)
|
||||
{
|
||||
INT32 max;
|
||||
UINT32 intSave;
|
||||
INT32 i;
|
||||
|
||||
SCHEDULER_LOCK(intSave);
|
||||
max = g_edfNodePointer;
|
||||
g_edfNodePointer = EDF_DEBUG_NODE + 1;
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
|
||||
PRINTK("\r\nlast %d sched is: (in microsecond)\r\n", EDF_DEBUG_NODE);
|
||||
|
||||
PRINTK(" TID RunTime Deadline Period StartTime "
|
||||
"CurPeriod NextPeriod AllRun RealRun TimeOut WaitTime Status\n");
|
||||
|
||||
for (i = max; i < EDF_DEBUG_NODE; i++) {
|
||||
EDFInfoPrint(i);
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
EDFInfoPrint(i);
|
||||
}
|
||||
|
||||
SCHEDULER_LOCK(intSave);
|
||||
g_edfNodePointer = max;
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
}
|
||||
|
||||
UINT32 OsShellShowEdfSchedStatistics(VOID)
|
||||
{
|
||||
UINT32 intSave;
|
||||
LosTaskCB task;
|
||||
UINT64 curTime;
|
||||
UINT64 deadline;
|
||||
UINT64 finishTime;
|
||||
SchedEDF *sched = NULL;
|
||||
|
||||
PRINTK("Now Alive EDF Thread:\n");
|
||||
PRINTK("TID CurTime DeadTime FinishTime taskName\n");
|
||||
|
||||
for (UINT32 tid = 0; tid < g_taskMaxNum; tid++) {
|
||||
LosTaskCB *taskCB = g_taskCBArray + tid;
|
||||
SCHEDULER_LOCK(intSave);
|
||||
if (OsTaskIsUnused(taskCB)) {
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
continue;
|
||||
}
|
||||
|
||||
sched = (SchedEDF *)&taskCB->sp;
|
||||
if (sched->policy != LOS_SCHED_DEADLINE) {
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
continue;
|
||||
}
|
||||
|
||||
(VOID)memcpy_s(&task, sizeof(LosTaskCB), taskCB, sizeof(LosTaskCB));
|
||||
|
||||
curTime = OS_SYS_CYCLE_TO_US(HalClockGetCycles());
|
||||
finishTime = OS_SYS_CYCLE_TO_US(sched->finishTime);
|
||||
deadline = OS_SYS_CYCLE_TO_US(taskCB->ops->deadlineGet(taskCB));
|
||||
SCHEDULER_UNLOCK(intSave);
|
||||
|
||||
PRINTK("%3u%15llu%15llu%15llu %-32s\n",
|
||||
task.taskID, curTime, deadline, finishTime, task.taskName);
|
||||
}
|
||||
|
||||
OsEDFDebugPrint();
|
||||
|
||||
return LOS_OK;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user