mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-16 21:05:35 +03:00
Add TASK_AGE_EXPEDITE_RX to ensure RX task is never starved of time
This commit is contained in:
parent
c05ad2ec9b
commit
4e47a792d8
3 changed files with 18 additions and 10 deletions
|
@ -92,6 +92,8 @@ static FAST_DATA_ZERO_INIT bool gyroEnabled;
|
||||||
static int32_t desiredPeriodCycles;
|
static int32_t desiredPeriodCycles;
|
||||||
static uint32_t lastTargetCycles;
|
static uint32_t lastTargetCycles;
|
||||||
|
|
||||||
|
static uint8_t skippedRxAttempts = 0;
|
||||||
|
|
||||||
#if defined(USE_LATE_TASK_STATISTICS)
|
#if defined(USE_LATE_TASK_STATISTICS)
|
||||||
static int16_t lateTaskCount = 0;
|
static int16_t lateTaskCount = 0;
|
||||||
static uint32_t lateTaskTotal = 0;
|
static uint32_t lateTaskTotal = 0;
|
||||||
|
@ -569,8 +571,8 @@ FAST_CODE void scheduler(void)
|
||||||
if (task->attr->checkFunc) {
|
if (task->attr->checkFunc) {
|
||||||
// Increase priority for event driven tasks
|
// Increase priority for event driven tasks
|
||||||
if (task->dynamicPriority > 0) {
|
if (task->dynamicPriority > 0) {
|
||||||
task->taskAgeCycles = 1 + (cmpTimeUs(currentTimeUs, task->lastSignaledAtUs) / task->attr->desiredPeriodUs);
|
task->taskAgePeriods = 1 + (cmpTimeUs(currentTimeUs, task->lastSignaledAtUs) / task->attr->desiredPeriodUs);
|
||||||
task->dynamicPriority = 1 + task->attr->staticPriority * task->taskAgeCycles;
|
task->dynamicPriority = 1 + task->attr->staticPriority * task->taskAgePeriods;
|
||||||
} else if (task->attr->checkFunc(currentTimeUs, cmpTimeUs(currentTimeUs, task->lastExecutedAtUs))) {
|
} else if (task->attr->checkFunc(currentTimeUs, cmpTimeUs(currentTimeUs, task->lastExecutedAtUs))) {
|
||||||
const uint32_t checkFuncExecutionTimeUs = cmpTimeUs(micros(), currentTimeUs);
|
const uint32_t checkFuncExecutionTimeUs = cmpTimeUs(micros(), currentTimeUs);
|
||||||
#if !defined(UNIT_TEST)
|
#if !defined(UNIT_TEST)
|
||||||
|
@ -581,17 +583,17 @@ FAST_CODE void scheduler(void)
|
||||||
checkFuncTotalExecutionTimeUs += checkFuncExecutionTimeUs; // time consumed by scheduler + task
|
checkFuncTotalExecutionTimeUs += checkFuncExecutionTimeUs; // time consumed by scheduler + task
|
||||||
checkFuncMaxExecutionTimeUs = MAX(checkFuncMaxExecutionTimeUs, checkFuncExecutionTimeUs);
|
checkFuncMaxExecutionTimeUs = MAX(checkFuncMaxExecutionTimeUs, checkFuncExecutionTimeUs);
|
||||||
task->lastSignaledAtUs = currentTimeUs;
|
task->lastSignaledAtUs = currentTimeUs;
|
||||||
task->taskAgeCycles = 1;
|
task->taskAgePeriods = 1;
|
||||||
task->dynamicPriority = 1 + task->attr->staticPriority;
|
task->dynamicPriority = 1 + task->attr->staticPriority;
|
||||||
} else {
|
} else {
|
||||||
task->taskAgeCycles = 0;
|
task->taskAgePeriods = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Task is time-driven, dynamicPriority is last execution age (measured in desiredPeriods)
|
// Task is time-driven, dynamicPriority is last execution age (measured in desiredPeriods)
|
||||||
// Task age is calculated from last execution
|
// Task age is calculated from last execution
|
||||||
task->taskAgeCycles = (cmpTimeUs(currentTimeUs, task->lastExecutedAtUs) / task->attr->desiredPeriodUs);
|
task->taskAgePeriods = (cmpTimeUs(currentTimeUs, task->lastExecutedAtUs) / task->attr->desiredPeriodUs);
|
||||||
if (task->taskAgeCycles > 0) {
|
if (task->taskAgePeriods > 0) {
|
||||||
task->dynamicPriority = 1 + task->attr->staticPriority * task->taskAgeCycles;
|
task->dynamicPriority = 1 + task->attr->staticPriority * task->taskAgePeriods;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,6 +635,10 @@ FAST_CODE void scheduler(void)
|
||||||
}
|
}
|
||||||
#endif // USE_LATE_TASK_STATISTICS
|
#endif // USE_LATE_TASK_STATISTICS
|
||||||
|
|
||||||
|
if ((currentTask - tasks) == TASK_RX) {
|
||||||
|
skippedRxAttempts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((cyclesOverdue > 0) || (-cyclesOverdue < taskGuardMinCycles)) {
|
if ((cyclesOverdue > 0) || (-cyclesOverdue < taskGuardMinCycles)) {
|
||||||
if (taskGuardCycles < taskGuardMaxCycles) {
|
if (taskGuardCycles < taskGuardMaxCycles) {
|
||||||
taskGuardCycles += taskGuardDeltaUpCycles;
|
taskGuardCycles += taskGuardDeltaUpCycles;
|
||||||
|
@ -643,7 +649,8 @@ FAST_CODE void scheduler(void)
|
||||||
#if defined(USE_LATE_TASK_STATISTICS)
|
#if defined(USE_LATE_TASK_STATISTICS)
|
||||||
taskCount++;
|
taskCount++;
|
||||||
#endif // USE_LATE_TASK_STATISTICS
|
#endif // USE_LATE_TASK_STATISTICS
|
||||||
} else if (selectedTask->taskAgeCycles > TASK_AGE_EXPEDITE_COUNT) {
|
} else if ((selectedTask->taskAgePeriods > TASK_AGE_EXPEDITE_COUNT) ||
|
||||||
|
(((selectedTask - tasks) == TASK_RX) && (++skippedRxAttempts > TASK_AGE_EXPEDITE_RX))) {
|
||||||
// If a task has been unable to run, then reduce it's recorded estimated run time to ensure
|
// If a task has been unable to run, then reduce it's recorded estimated run time to ensure
|
||||||
// it's ultimate scheduling
|
// it's ultimate scheduling
|
||||||
selectedTask->anticipatedExecutionTime *= TASK_AGE_EXPEDITE_SCALE;
|
selectedTask->anticipatedExecutionTime *= TASK_AGE_EXPEDITE_SCALE;
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
// Decay the estimated max task duration by 1/(1 << TASK_EXEC_TIME_SHIFT) on every invocation
|
// Decay the estimated max task duration by 1/(1 << TASK_EXEC_TIME_SHIFT) on every invocation
|
||||||
#define TASK_EXEC_TIME_SHIFT 7
|
#define TASK_EXEC_TIME_SHIFT 7
|
||||||
|
|
||||||
|
#define TASK_AGE_EXPEDITE_RX 25 // Make RX tasks more schedulable if it's failed to be scheduled this many times
|
||||||
#define TASK_AGE_EXPEDITE_COUNT 1 // Make aged tasks more schedulable
|
#define TASK_AGE_EXPEDITE_COUNT 1 // Make aged tasks more schedulable
|
||||||
#define TASK_AGE_EXPEDITE_SCALE 0.9 // By scaling their expected execution time
|
#define TASK_AGE_EXPEDITE_SCALE 0.9 // By scaling their expected execution time
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ typedef struct {
|
||||||
|
|
||||||
// Scheduling
|
// Scheduling
|
||||||
uint16_t dynamicPriority; // measurement of how old task was last executed, used to avoid task starvation
|
uint16_t dynamicPriority; // measurement of how old task was last executed, used to avoid task starvation
|
||||||
uint16_t taskAgeCycles;
|
uint16_t taskAgePeriods;
|
||||||
timeDelta_t taskLatestDeltaTimeUs;
|
timeDelta_t taskLatestDeltaTimeUs;
|
||||||
timeUs_t lastExecutedAtUs; // last time of invocation
|
timeUs_t lastExecutedAtUs; // last time of invocation
|
||||||
timeUs_t lastSignaledAtUs; // time of invocation event for event-driven tasks
|
timeUs_t lastSignaledAtUs; // time of invocation event for event-driven tasks
|
||||||
|
|
|
@ -396,7 +396,7 @@ TEST(SchedulerUnittest, TestTwoTasks)
|
||||||
simulatedTime = startTime;
|
simulatedTime = startTime;
|
||||||
tasks[TASK_ACCEL].lastExecutedAtUs = simulatedTime;
|
tasks[TASK_ACCEL].lastExecutedAtUs = simulatedTime;
|
||||||
tasks[TASK_ATTITUDE].lastExecutedAtUs = tasks[TASK_ACCEL].lastExecutedAtUs - TEST_UPDATE_ATTITUDE_TIME;
|
tasks[TASK_ATTITUDE].lastExecutedAtUs = tasks[TASK_ACCEL].lastExecutedAtUs - TEST_UPDATE_ATTITUDE_TIME;
|
||||||
EXPECT_EQ(0, tasks[TASK_ATTITUDE].taskAgeCycles);
|
EXPECT_EQ(0, tasks[TASK_ATTITUDE].taskAgePeriods);
|
||||||
// run the scheduler
|
// run the scheduler
|
||||||
scheduler();
|
scheduler();
|
||||||
// no tasks should have run, since neither task's desired time has elapsed
|
// no tasks should have run, since neither task's desired time has elapsed
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue