1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-23 16:25:31 +03:00

Initial commit of run queue for scheduler.

This commit is contained in:
Martin Budden 2016-01-18 19:01:56 +00:00 committed by borisbstyle
parent bab2c72ae0
commit 5a9523c26b
3 changed files with 112 additions and 88 deletions

View file

@ -721,6 +721,7 @@ int main(void) {
setTaskEnabled(TASK_TRANSPONDER, feature(FEATURE_TRANSPONDER)); setTaskEnabled(TASK_TRANSPONDER, feature(FEATURE_TRANSPONDER));
#endif #endif
schedulerInit();
while (1) { while (1) {
scheduler(); scheduler();
processLoopback(); processLoopback();

View file

@ -30,7 +30,7 @@
#include "drivers/system.h" #include "drivers/system.h"
cfTaskId_e currentTaskId = TASK_NONE; static cfTask_t *currentTask = NULL;
#define REALTIME_GUARD_INTERVAL_MIN 10 #define REALTIME_GUARD_INTERVAL_MIN 10
#define REALTIME_GUARD_INTERVAL_MAX 300 #define REALTIME_GUARD_INTERVAL_MAX 300
@ -44,10 +44,42 @@ uint32_t currentTime = 0;
uint16_t averageSystemLoadPercent = 0; uint16_t averageSystemLoadPercent = 0;
static int queuePos = 0;
static int queueSize = 0;
static cfTask_t* queueArray[TASK_COUNT];
static void queueInit(void)
{
queuePos = 0;
queueSize = 0;
// put the enabled tasks in the queue in priority order
const cfTaskPriority_e priorities[] =
{TASK_PRIORITY_MAX, TASK_PRIORITY_REALTIME, TASK_PRIORITY_HIGH, TASK_PRIORITY_MEDIUM, TASK_PRIORITY_LOW, TASK_PRIORITY_IDLE};
for (unsigned int ii = 0; ii < sizeof(priorities); ++ii) {
const cfTaskPriority_e priority = priorities[ii];
for (int taskId = 0; taskId < TASK_COUNT; ++taskId) {
cfTask_t *task = &cfTasks[taskId];
if (task->staticPriority == priority && task->isEnabled == true) {
queueArray[queuePos] = task;
++queuePos;
++queueSize;
}
}
}
}
static cfTask_t *queueFirst(void)
{
queuePos = 0;
return queueSize > 0 ? queueArray[0] : NULL;
}
static cfTask_t *queueNext(void) {
++queuePos;
return queuePos < queueSize ? queueArray[queuePos] : NULL;
}
void taskSystem(void) void taskSystem(void)
{ {
uint8_t taskId;
/* Calculate system load */ /* Calculate system load */
if (totalWaitingTasksSamples > 0) { if (totalWaitingTasksSamples > 0) {
averageSystemLoadPercent = 100 * totalWaitingTasks / totalWaitingTasksSamples; averageSystemLoadPercent = 100 * totalWaitingTasks / totalWaitingTasksSamples;
@ -57,9 +89,9 @@ void taskSystem(void)
/* Calculate guard interval */ /* Calculate guard interval */
uint32_t maxNonRealtimeTaskTime = 0; uint32_t maxNonRealtimeTaskTime = 0;
for (taskId = 0; taskId < TASK_COUNT; taskId++) { for (const cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) {
if (cfTasks[taskId].staticPriority != TASK_PRIORITY_REALTIME) { if (task->staticPriority != TASK_PRIORITY_REALTIME) {
maxNonRealtimeTaskTime = MAX(maxNonRealtimeTaskTime, cfTasks[taskId].averageExecutionTime); maxNonRealtimeTaskTime = MAX(maxNonRealtimeTaskTime, task->averageExecutionTime);
} }
} }
@ -84,108 +116,100 @@ void getTaskInfo(cfTaskId_e taskId, cfTaskInfo_t * taskInfo)
void rescheduleTask(cfTaskId_e taskId, uint32_t newPeriodMicros) void rescheduleTask(cfTaskId_e taskId, uint32_t newPeriodMicros)
{ {
if (taskId == TASK_SELF) if (taskId == TASK_SELF || taskId < TASK_COUNT) {
taskId = currentTaskId; cfTask_t *task = taskId == TASK_SELF ? currentTask : &cfTasks[taskId];
task->desiredPeriod = MAX(100, newPeriodMicros); // Limit delay to 100us (10 kHz) to prevent scheduler clogging
if (taskId < TASK_COUNT) {
cfTasks[taskId].desiredPeriod = MAX(100, newPeriodMicros); // Limit delay to 100us (10 kHz) to prevent scheduler clogging
} }
} }
void setTaskEnabled(cfTaskId_e taskId, bool newEnabledState) void setTaskEnabled(cfTaskId_e taskId, bool newEnabledState)
{ {
if (taskId == TASK_SELF) if (taskId == TASK_SELF || taskId < TASK_COUNT) {
taskId = currentTaskId; cfTask_t *task = taskId == TASK_SELF ? currentTask : &cfTasks[taskId];
task->isEnabled = newEnabledState;
if (taskId < TASK_COUNT) {
cfTasks[taskId].isEnabled = newEnabledState;
} }
} }
uint32_t getTaskDeltaTime(cfTaskId_e taskId) uint32_t getTaskDeltaTime(cfTaskId_e taskId)
{ {
if (taskId == TASK_SELF) if (taskId == TASK_SELF || taskId < TASK_COUNT) {
taskId = currentTaskId; cfTask_t *task = taskId == TASK_SELF ? currentTask : &cfTasks[taskId];
return task->taskLatestDeltaTime;
if (taskId < TASK_COUNT) { } else {
return cfTasks[taskId].taskLatestDeltaTime;
}
else {
return 0; return 0;
} }
} }
void schedulerInit(void)
{
queueInit();
}
void scheduler(void) void scheduler(void)
{ {
uint8_t taskId;
/* The task to be invoked */
uint8_t selectedTaskId = TASK_NONE;
uint8_t selectedTaskDynPrio = 0;
uint16_t waitingTasks = 0;
uint32_t timeToNextRealtimeTask = UINT32_MAX;
SET_SCHEDULER_LOCALS();
/* Cache currentTime */ /* Cache currentTime */
currentTime = micros(); currentTime = micros();
/* Check for realtime tasks */ /* Check for realtime tasks */
for (taskId = 0; taskId < TASK_COUNT; taskId++) { uint32_t timeToNextRealtimeTask = UINT32_MAX;
if (cfTasks[taskId].staticPriority == TASK_PRIORITY_REALTIME) { for (const cfTask_t *task = queueFirst(); task != NULL && task->staticPriority >= TASK_PRIORITY_REALTIME; task = queueNext()) {
uint32_t nextExecuteAt = cfTasks[taskId].lastExecutedAt + cfTasks[taskId].desiredPeriod; const uint32_t nextExecuteAt = task->lastExecutedAt + task->desiredPeriod;
if ((int32_t)(currentTime - nextExecuteAt) >= 0) { if ((int32_t)(currentTime - nextExecuteAt) >= 0) {
timeToNextRealtimeTask = 0; timeToNextRealtimeTask = 0;
} }
else { else {
uint32_t newTimeInterval = nextExecuteAt - currentTime; const uint32_t newTimeInterval = nextExecuteAt - currentTime;
timeToNextRealtimeTask = MIN(timeToNextRealtimeTask, newTimeInterval); timeToNextRealtimeTask = MIN(timeToNextRealtimeTask, newTimeInterval);
} }
} }
}
bool outsideRealtimeGuardInterval = (timeToNextRealtimeTask > realtimeGuardInterval); /* The task to be invoked */
uint8_t selectedTaskDynPrio = 0;
cfTask_t *selectedTask = NULL;
/* Update task dynamic priorities */ /* Update task dynamic priorities */
for (taskId = 0; taskId < TASK_COUNT; taskId++) { uint16_t waitingTasks = 0;
if (cfTasks[taskId].isEnabled) { for (cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) {
/* Task has checkFunc - event driven */ /* Task has checkFunc - event driven */
if (cfTasks[taskId].checkFunc != NULL) { if (task->checkFunc != NULL) {
/* Increase priority for event driven tasks */ /* Increase priority for event driven tasks */
if (cfTasks[taskId].dynamicPriority > 0) { if (task->dynamicPriority > 0) {
cfTasks[taskId].taskAgeCycles = 1 + ((currentTime - cfTasks[taskId].lastSignaledAt) / cfTasks[taskId].desiredPeriod); task->taskAgeCycles = 1 + ((currentTime - task->lastSignaledAt) / task->desiredPeriod);
cfTasks[taskId].dynamicPriority = 1 + cfTasks[taskId].staticPriority * cfTasks[taskId].taskAgeCycles; task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles;
waitingTasks++; waitingTasks++;
} }
else if (cfTasks[taskId].checkFunc(currentTime - cfTasks[taskId].lastExecutedAt)) { else if (task->checkFunc(currentTime - task->lastExecutedAt)) {
cfTasks[taskId].lastSignaledAt = currentTime; task->lastSignaledAt = currentTime;
cfTasks[taskId].taskAgeCycles = 1; task->taskAgeCycles = 1;
cfTasks[taskId].dynamicPriority = 1 + cfTasks[taskId].staticPriority; task->dynamicPriority = 1 + task->staticPriority;
waitingTasks++; waitingTasks++;
} }
else { else {
cfTasks[taskId].taskAgeCycles = 0; task->taskAgeCycles = 0;
} }
} }
/* Task is time-driven, dynamicPriority is last execution age measured in desiredPeriods) */ /* Task is time-driven, dynamicPriority is last execution age measured in desiredPeriods) */
else { else {
// Task age is calculated from last execution // Task age is calculated from last execution
cfTasks[taskId].taskAgeCycles = ((currentTime - cfTasks[taskId].lastExecutedAt) / cfTasks[taskId].desiredPeriod); task->taskAgeCycles = ((currentTime - task->lastExecutedAt) / task->desiredPeriod);
if (cfTasks[taskId].taskAgeCycles > 0) { if (task->taskAgeCycles > 0) {
cfTasks[taskId].dynamicPriority = 1 + cfTasks[taskId].staticPriority * cfTasks[taskId].taskAgeCycles; task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles;
waitingTasks++; waitingTasks++;
} }
} }
/* limit new priority to avoid overflow of uint8_t */ /* limit new priority to avoid overflow of uint8_t */
cfTasks[taskId].dynamicPriority = MIN(cfTasks[taskId].dynamicPriority, TASK_PRIORITY_MAX);; task->dynamicPriority = MIN(task->dynamicPriority, TASK_PRIORITY_MAX);;
if (task->dynamicPriority > selectedTaskDynPrio) {
const bool outsideRealtimeGuardInterval = (timeToNextRealtimeTask > realtimeGuardInterval);
bool taskCanBeChosenForScheduling = bool taskCanBeChosenForScheduling =
(outsideRealtimeGuardInterval) || (outsideRealtimeGuardInterval) ||
(cfTasks[taskId].taskAgeCycles > 1) || (task->taskAgeCycles > 1) ||
(cfTasks[taskId].staticPriority == TASK_PRIORITY_REALTIME); (task->staticPriority == TASK_PRIORITY_REALTIME);
if (taskCanBeChosenForScheduling) {
if (taskCanBeChosenForScheduling && (cfTasks[taskId].dynamicPriority > selectedTaskDynPrio)) { selectedTaskDynPrio = task->dynamicPriority;
selectedTaskDynPrio = cfTasks[taskId].dynamicPriority; selectedTask = task;
selectedTaskId = taskId;
} }
} }
} }
@ -194,33 +218,31 @@ void scheduler(void)
totalWaitingTasks += waitingTasks; totalWaitingTasks += waitingTasks;
/* Found a task that should be run */ /* Found a task that should be run */
if (selectedTaskId != TASK_NONE) { if (selectedTask != NULL) {
cfTasks[selectedTaskId].taskLatestDeltaTime = currentTime - cfTasks[selectedTaskId].lastExecutedAt; selectedTask->taskLatestDeltaTime = currentTime - selectedTask->lastExecutedAt;
cfTasks[selectedTaskId].lastExecutedAt = currentTime; selectedTask->lastExecutedAt = currentTime;
cfTasks[selectedTaskId].dynamicPriority = 0; selectedTask->dynamicPriority = 0;
currentTaskId = selectedTaskId; currentTask = selectedTask;
uint32_t currentTimeBeforeTaskCall = micros(); uint32_t currentTimeBeforeTaskCall = micros();
/* Execute task */ /* Execute task */
if (cfTasks[selectedTaskId].taskFunc != NULL) { selectedTask->taskFunc();
cfTasks[selectedTaskId].taskFunc();
}
uint32_t taskExecutionTime = micros() - currentTimeBeforeTaskCall; uint32_t taskExecutionTime = micros() - currentTimeBeforeTaskCall;
cfTasks[selectedTaskId].averageExecutionTime = ((uint32_t)cfTasks[selectedTaskId].averageExecutionTime * 31 + taskExecutionTime) / 32; selectedTask->averageExecutionTime = ((uint32_t)selectedTask->averageExecutionTime * 31 + taskExecutionTime) / 32;
#ifndef SKIP_TASK_STATISTICS #ifndef SKIP_TASK_STATISTICS
cfTasks[selectedTaskId].totalExecutionTime += taskExecutionTime; // time consumed by scheduler + task selectedTask->totalExecutionTime += taskExecutionTime; // time consumed by scheduler + task
cfTasks[selectedTaskId].maxExecutionTime = MAX(cfTasks[selectedTaskId].maxExecutionTime, taskExecutionTime); selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime);
#endif #endif
#if defined SCHEDULER_DEBUG #if defined SCHEDULER_DEBUG
debug[3] = (micros() - currentTime) - taskExecutionTime; debug[3] = (micros() - currentTime) - taskExecutionTime;
#endif #endif
} }
else { else {
currentTaskId = TASK_NONE; currentTask = NULL;
#if defined SCHEDULER_DEBUG #if defined SCHEDULER_DEBUG
debug[3] = (micros() - currentTime); debug[3] = (micros() - currentTime);
#endif #endif

View file

@ -118,6 +118,7 @@ void rescheduleTask(cfTaskId_e taskId, uint32_t newPeriodMicros);
void setTaskEnabled(cfTaskId_e taskId, bool newEnabledState); void setTaskEnabled(cfTaskId_e taskId, bool newEnabledState);
uint32_t getTaskDeltaTime(cfTaskId_e taskId); uint32_t getTaskDeltaTime(cfTaskId_e taskId);
void schedulerInit(void);
void scheduler(void); void scheduler(void);
#define LOAD_PERCENTAGE_ONE 100 #define LOAD_PERCENTAGE_ONE 100