Improved scheduler and task timing instrumentation

This commit is contained in:
Martin Budden 2016-11-26 12:39:05 +00:00
parent ccd759d93a
commit 4fe68ce093
10 changed files with 71 additions and 30 deletions

View File

@ -60,5 +60,6 @@ typedef enum {
DEBUG_DTERM_FILTER, DEBUG_DTERM_FILTER,
DEBUG_ANGLERATE, DEBUG_ANGLERATE,
DEBUG_ESC_TELEMETRY, DEBUG_ESC_TELEMETRY,
DEBUG_SCHEDULER,
DEBUG_COUNT DEBUG_COUNT
} debugType_e; } debugType_e;

View File

@ -582,7 +582,7 @@ void createDefaultConfig(master_t *config)
config->gyroConfig.gyro_soft_notch_hz_2 = 200; config->gyroConfig.gyro_soft_notch_hz_2 = 200;
config->gyroConfig.gyro_soft_notch_cutoff_2 = 100; config->gyroConfig.gyro_soft_notch_cutoff_2 = 100;
config->debug_mode = DEBUG_NONE; config->debug_mode = DEBUG_MODE;
resetAccelerometerTrims(&config->sensorTrims.accZero); resetAccelerometerTrims(&config->sensorTrims.accZero);

View File

@ -72,6 +72,10 @@
#include "config/config_profile.h" #include "config/config_profile.h"
#include "config/config_master.h" #include "config/config_master.h"
#ifdef USE_BST
void taskBstMasterProcess(uint32_t currentTime);
#endif
#define TASK_PERIOD_HZ(hz) (1000000 / (hz)) #define TASK_PERIOD_HZ(hz) (1000000 / (hz))
#define TASK_PERIOD_MS(ms) ((ms) * 1000) #define TASK_PERIOD_MS(ms) ((ms) * 1000)
#define TASK_PERIOD_US(us) (us) #define TASK_PERIOD_US(us) (us)
@ -295,7 +299,7 @@ cfTask_t cfTasks[TASK_COUNT] = {
[TASK_GYROPID] = { [TASK_GYROPID] = {
.taskName = "PID", .taskName = "PID",
.subTaskName = "GYRO", .subTaskName = "GYRO",
.taskFunc = taskMainPidLoopCheck, .taskFunc = taskMainPidLoop,
.desiredPeriod = TASK_GYROPID_DESIRED_PERIOD, .desiredPeriod = TASK_GYROPID_DESIRED_PERIOD,
.staticPriority = TASK_PRIORITY_REALTIME, .staticPriority = TASK_PRIORITY_REALTIME,
}, },

View File

@ -19,11 +19,4 @@
#define LOOPTIME_SUSPEND_TIME 3 // Prevent too long busy wait times #define LOOPTIME_SUSPEND_TIME 3 // Prevent too long busy wait times
void taskSystem(uint32_t currentTime);
void taskMainPidLoopCheck(uint32_t currentTime);
#ifdef USE_BST
void taskBstReadWrite(uint32_t currentTime);
void taskBstMasterProcess(uint32_t currentTime);
#endif
void fcTasksInit(void); void fcTasksInit(void);

View File

@ -177,9 +177,7 @@ void calculateSetpointRate(int axis, int16_t rc) {
angleRate *= rcSuperfactor; angleRate *= rcSuperfactor;
} }
if (debugMode == DEBUG_ANGLERATE) { DEBUG_SET(DEBUG_ANGLERATE, axis, angleRate);
debug[axis] = angleRate;
}
setpointRate[axis] = constrainf(angleRate, -1998.0f, 1998.0f); // Rate limit protection (deg/sec) setpointRate[axis] = constrainf(angleRate, -1998.0f, 1998.0f); // Rate limit protection (deg/sec)
} }
@ -687,7 +685,7 @@ void processRx(uint32_t currentTime)
void subTaskPidController(void) void subTaskPidController(void)
{ {
uint32_t startTime; uint32_t startTime;
if (debugMode == DEBUG_PIDLOOP) {startTime = micros();} if (debugMode == DEBUG_PIDLOOP || debugMode == DEBUG_SCHEDULER) {startTime = micros();}
// PID - note this is function pointer set by setPIDController() // PID - note this is function pointer set by setPIDController()
pidController( pidController(
&currentProfile->pidProfile, &currentProfile->pidProfile,
@ -695,7 +693,7 @@ void subTaskPidController(void)
&masterConfig.accelerometerTrims, &masterConfig.accelerometerTrims,
masterConfig.rxConfig.midrc masterConfig.rxConfig.midrc
); );
if (debugMode == DEBUG_PIDLOOP) {debug[2] = micros() - startTime;} if (debugMode == DEBUG_PIDLOOP || debugMode == DEBUG_SCHEDULER) {debug[1] = micros() - startTime;}
} }
void subTaskMainSubprocesses(void) void subTaskMainSubprocesses(void)
@ -772,7 +770,7 @@ void subTaskMainSubprocesses(void)
#ifdef TRANSPONDER #ifdef TRANSPONDER
transponderUpdate(startTime); transponderUpdate(startTime);
#endif #endif
if (debugMode == DEBUG_PIDLOOP) {debug[1] = micros() - startTime;} DEBUG_SET(DEBUG_PIDLOOP, 2, micros() - startTime);
} }
void subTaskMotorUpdate(void) void subTaskMotorUpdate(void)
@ -798,7 +796,7 @@ void subTaskMotorUpdate(void)
if (motorControlEnable) { if (motorControlEnable) {
writeMotors(); writeMotors();
} }
if (debugMode == DEBUG_PIDLOOP) {debug[3] = micros() - startTime;} DEBUG_SET(DEBUG_PIDLOOP, 3, micros() - startTime);
} }
uint8_t setPidUpdateCountDown(void) uint8_t setPidUpdateCountDown(void)
@ -811,7 +809,7 @@ uint8_t setPidUpdateCountDown(void)
} }
// Function for loop trigger // Function for loop trigger
void taskMainPidLoopCheck(uint32_t currentTime) void taskMainPidLoop(uint32_t currentTime)
{ {
UNUSED(currentTime); UNUSED(currentTime);
@ -830,7 +828,15 @@ void taskMainPidLoopCheck(uint32_t currentTime)
runTaskMainSubprocesses = false; runTaskMainSubprocesses = false;
} }
// DEBUG_PIDLOOP
// 0 - gyroUpdate()
// 1 - pidController()
// 2 - subTaskMainSubprocesses()
// 3 - subTaskMotorUpdate()
uint32_t startTime;
if (debugMode == DEBUG_PIDLOOP || debugMode == DEBUG_SCHEDULER) {startTime = micros();}
gyroUpdate(); gyroUpdate();
if (debugMode == DEBUG_PIDLOOP || debugMode == DEBUG_SCHEDULER) {debug[0] = micros() - startTime;}
if (pidUpdateCountdown) { if (pidUpdateCountdown) {
pidUpdateCountdown--; pidUpdateCountdown--;

View File

@ -31,3 +31,4 @@ void processRx(uint32_t currentTime);
void updateLEDs(void); void updateLEDs(void);
void updateRcCommands(void); void updateRcCommands(void);
void taskMainPidLoop(uint32_t currentTime);

View File

@ -519,6 +519,7 @@ static const char * const lookupTableDebug[DEBUG_COUNT] = {
"DFILTER", "DFILTER",
"ANGLERATE", "ANGLERATE",
"ESC_TELEMETRY", "ESC_TELEMETRY",
"SCHEDULER",
}; };
#ifdef OSD #ifdef OSD
@ -3643,6 +3644,9 @@ static void cliTasks(char *cmdline)
} }
} }
} }
cfCheckFuncInfo_t checkFuncInfo;
getCheckFuncInfo(&checkFuncInfo);
cliPrintf("RX Check Function %17d %7d %25d\r\n", checkFuncInfo.maxExecutionTime, checkFuncInfo.averageExecutionTime, checkFuncInfo.totalExecutionTime / 1000);
cliPrintf("Total (excluding SERIAL) %23d.%1d%% %4d.%1d%%\r\n", maxLoadSum/10, maxLoadSum%10, averageLoadSum/10, averageLoadSum%10); cliPrintf("Total (excluding SERIAL) %23d.%1d%% %4d.%1d%%\r\n", maxLoadSum/10, maxLoadSum%10, averageLoadSum/10, averageLoadSum%10);
} }
#endif #endif

View File

@ -121,6 +121,17 @@ void taskSystem(uint32_t currentTime)
} }
#ifndef SKIP_TASK_STATISTICS #ifndef SKIP_TASK_STATISTICS
uint32_t checkFuncMaxExecutionTime;
uint32_t checkFuncTotalExecutionTime;
uint32_t checkFuncAverageExecutionTime;
void getCheckFuncInfo(cfCheckFuncInfo_t *checkFuncInfo)
{
checkFuncInfo->maxExecutionTime = checkFuncMaxExecutionTime;
checkFuncInfo->totalExecutionTime = checkFuncTotalExecutionTime;
checkFuncInfo->averageExecutionTime = checkFuncAverageExecutionTime;
}
void getTaskInfo(cfTaskId_e taskId, cfTaskInfo_t * taskInfo) void getTaskInfo(cfTaskId_e taskId, cfTaskInfo_t * taskInfo)
{ {
taskInfo->taskName = cfTasks[taskId].taskName; taskInfo->taskName = cfTasks[taskId].taskName;
@ -198,13 +209,25 @@ void scheduler(void)
for (cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) { for (cfTask_t *task = queueFirst(); task != NULL; task = queueNext()) {
// Task has checkFunc - event driven // Task has checkFunc - event driven
if (task->checkFunc != NULL) { if (task->checkFunc != NULL) {
const uint32_t currentTimeBeforeCheckFuncCall = micros();
// Increase priority for event driven tasks // Increase priority for event driven tasks
if (task->dynamicPriority > 0) { if (task->dynamicPriority > 0) {
task->taskAgeCycles = 1 + ((currentTime - task->lastSignaledAt) / task->desiredPeriod); task->taskAgeCycles = 1 + ((currentTime - task->lastSignaledAt) / task->desiredPeriod);
task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles; task->dynamicPriority = 1 + task->staticPriority * task->taskAgeCycles;
waitingTasks++; waitingTasks++;
} else if (task->checkFunc(currentTime, currentTime - task->lastExecutedAt)) { } else if (task->checkFunc(currentTimeBeforeCheckFuncCall, currentTimeBeforeCheckFuncCall - task->lastExecutedAt)) {
task->lastSignaledAt = currentTime; #if defined(SCHEDULER_DEBUG) || !defined(SKIP_TASK_STATISTICS)
const uint32_t checkFuncExecutionTime = micros() - currentTimeBeforeCheckFuncCall;
#endif
#if defined(SCHEDULER_DEBUG)
DEBUG_SET(DEBUG_SCHEDULER, 3, checkFuncExecutionTime);
#endif
#ifndef SKIP_TASK_STATISTICS
checkFuncAverageExecutionTime = (checkFuncAverageExecutionTime * 31 + checkFuncExecutionTime) / 32;
checkFuncTotalExecutionTime += checkFuncExecutionTime; // time consumed by scheduler + task
checkFuncMaxExecutionTime = MAX(checkFuncMaxExecutionTime, checkFuncExecutionTime);
#endif
task->lastSignaledAt = currentTimeBeforeCheckFuncCall;
task->taskAgeCycles = 1; task->taskAgeCycles = 1;
task->dynamicPriority = 1 + task->staticPriority; task->dynamicPriority = 1 + task->staticPriority;
waitingTasks++; waitingTasks++;
@ -247,17 +270,17 @@ void scheduler(void)
// Execute task // Execute task
const uint32_t currentTimeBeforeTaskCall = micros(); const uint32_t currentTimeBeforeTaskCall = micros();
selectedTask->taskFunc(currentTimeBeforeTaskCall); selectedTask->taskFunc(currentTimeBeforeTaskCall);
const uint32_t taskExecutionTime = micros() - currentTimeBeforeTaskCall;
selectedTask->averageExecutionTime = ((uint32_t)selectedTask->averageExecutionTime * 31 + taskExecutionTime) / 32;
#ifndef SKIP_TASK_STATISTICS #ifndef SKIP_TASK_STATISTICS
const uint32_t taskExecutionTime = micros() - currentTimeBeforeTaskCall;
selectedTask->averageExecutionTime = ((uint32_t)selectedTask->averageExecutionTime * 31 + taskExecutionTime) / 32;
selectedTask->totalExecutionTime += taskExecutionTime; // time consumed by scheduler + task selectedTask->totalExecutionTime += taskExecutionTime; // time consumed by scheduler + task
selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime); selectedTask->maxExecutionTime = MAX(selectedTask->maxExecutionTime, taskExecutionTime);
#endif #endif
#if defined SCHEDULER_DEBUG #if defined(SCHEDULER_DEBUG)
debug[3] = (micros() - currentTime) - taskExecutionTime; DEBUG_SET(DEBUG_SCHEDULER, 2, micros() - currentTime - taskExecutionTime); // time spent in scheduler
} else { } else {
debug[3] = (micros() - currentTime); DEBUG_SET(DEBUG_SCHEDULER, 2, micros() - currentTime);
#endif #endif
} }
} }

View File

@ -17,8 +17,6 @@
#pragma once #pragma once
//#define SCHEDULER_DEBUG
typedef enum { typedef enum {
TASK_PRIORITY_IDLE = 0, // Disables dynamic scheduling, task is executed only if no other task is active this cycle TASK_PRIORITY_IDLE = 0, // Disables dynamic scheduling, task is executed only if no other task is active this cycle
TASK_PRIORITY_LOW = 1, TASK_PRIORITY_LOW = 1,
@ -28,6 +26,12 @@ typedef enum {
TASK_PRIORITY_MAX = 255 TASK_PRIORITY_MAX = 255
} cfTaskPriority_e; } cfTaskPriority_e;
typedef struct {
uint32_t maxExecutionTime;
uint32_t totalExecutionTime;
uint32_t averageExecutionTime;
} cfCheckFuncInfo_t;
typedef struct { typedef struct {
const char * taskName; const char * taskName;
const char * subTaskName; const char * subTaskName;
@ -114,11 +118,11 @@ typedef struct {
uint16_t taskAgeCycles; uint16_t taskAgeCycles;
uint32_t lastExecutedAt; // last time of invocation uint32_t lastExecutedAt; // last time of invocation
uint32_t lastSignaledAt; // time of invocation event for event-driven tasks uint32_t lastSignaledAt; // time of invocation event for event-driven tasks
uint32_t taskLatestDeltaTime;
/* Statistics */
uint32_t averageExecutionTime; // Moving average over 6 samples, used to calculate guard interval
uint32_t taskLatestDeltaTime; //
#ifndef SKIP_TASK_STATISTICS #ifndef SKIP_TASK_STATISTICS
/* Statistics */
uint32_t averageExecutionTime; // Moving average over 32 samples
uint32_t maxExecutionTime; uint32_t maxExecutionTime;
uint32_t totalExecutionTime; // total time consumed by task since boot uint32_t totalExecutionTime; // total time consumed by task since boot
#endif #endif
@ -127,13 +131,15 @@ typedef struct {
extern cfTask_t cfTasks[TASK_COUNT]; extern cfTask_t cfTasks[TASK_COUNT];
extern uint16_t averageSystemLoadPercent; extern uint16_t averageSystemLoadPercent;
void getTaskInfo(cfTaskId_e taskId, cfTaskInfo_t * taskInfo); void getCheckFuncInfo(cfCheckFuncInfo_t *checkFuncInfo);
void getTaskInfo(cfTaskId_e taskId, cfTaskInfo_t *taskInfo);
void rescheduleTask(cfTaskId_e taskId, uint32_t newPeriodMicros); 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 schedulerInit(void);
void scheduler(void); void scheduler(void);
void taskSystem(uint32_t currentTime);
#define LOAD_PERCENTAGE_ONE 100 #define LOAD_PERCENTAGE_ONE 100

View File

@ -17,6 +17,9 @@
#pragma once #pragma once
//#define SCHEDULER_DEBUG // define this to use scheduler debug[] values. Undefined by default for performance reasons
#define DEBUG_MODE DEBUG_NONE // change this to change initial debug mode
#define I2C1_OVERCLOCK true #define I2C1_OVERCLOCK true
#define I2C2_OVERCLOCK true #define I2C2_OVERCLOCK true