Appearance
优化
栈的使用情况
在创建任务时分配了栈,可以填入固定的数值比如0xa5,以后可以使用以下函数查看"栈的高水位",也就是还有多少空余的栈空间:
c
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
原理是:从栈底往栈顶逐个字节地判断,它们的值持续是0xa5就表示它是空闲的。
任务运行时、任务被切换时,都会用到栈。栈里原来值(0xa5)就会被覆盖。逐个函数从栈的尾部判断栈的值连续为0xa5的个数,它就是任务运行过程中空闲内存容量的最小值。注意:假设从栈尾开始连续为0xa5的栈空间是N字节,返回值是N/4。
任务的运行时间统计
对于同优先级的任务,它们按照时间片轮流运行:你执行一个Tick,我执行一个Tick。
是否可以在Tick中断函数中,统计当前任务的累计运行时间?
不行!很不精确,因为有更高优先级的任务就绪时,当前任务还没运行一个完整的Tick就被抢占了。
我们需要比Tick更快的时钟,比如Tick周期时1ms,我们可以使用另一个定时器,让它发生中断的周期时0.1ms甚至更短。
使用这个定时器来衡量一个任务的运行时间
- 切换到Task1时,使用更快的定时器记录当前时间T1
- Task1被切换出去时,使用更快的定时器记录当前时间T4
- (T4-T1)就是它运行的时间,累加起来
- 关键点:在
vTaskSwitchContext
函数中,使用更快的定时器统计运行时间
还可以使用一个变量count记录当前的时钟中断的个数, 在任务切换的时候记录Timer的值, 在加上之前记录count从而获得精确地数值
配置
c
#define configGENERATE_RUN_TIME_STATS 1
//初始化这一个以后需要再定义一个初始化我们使用的时钟的函数
#define configCONFIGURE_TIMER_FOR_RUN_TIME_STATS Timer_Init
//一个获取这个时间的函数
/*
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
//记录总的运行时间
portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
#else
ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif
*/
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
- 实现宏
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
,它用来初始化更快的定时器 - 实现这两个宏之一,它们用来返回当前时钟值(更快的定时器)
- portGET_RUN_TIME_COUNTER_VALUE():直接返回时钟值
- portALT_GET_RUN_TIME_COUNTER_VALUE(Time):设置Time变量等于时钟值
可以使用初始化一个外设时钟, 之后使用这一个时钟进行获取时间
c
#if ( configGENERATE_RUN_TIME_STATS == 1 )
{
#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
//记录总的运行时间
portALT_GET_RUN_TIME_COUNTER_VALUE( ulTotalRunTime );
#else
ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
#endif
/* Add the amount of time the task has been running to the
* accumulated time so far. The time the task started running was
* stored in ulTaskSwitchedInTime. Note that there is no overflow
* protection here so count values are only valid until the timer
* overflows. The guard against negative values is to protect
* against suspect run time stat counter implementations - which
* are provided by the application, not the kernel. */
if( ulTotalRunTime > ulTaskSwitchedInTime )
{
pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
}//把这一次的运行时间进行累加
else
{
mtCOVERAGE_TEST_MARKER();
}
ulTaskSwitchedInTime = ulTotalRunTime;
}
#endif /* configGENERATE_RUN_TIME_STATS */
在切换任务的时候如果有这一个宏
信息获取
获得统计信息,可以使用下列函数
uxTaskGetSystemState:对于每个任务它的统计信息都放在一个TaskStatus_t结构体里
vTaskList:得到的信息是可读的字符串,比如
vTaskGetRunTimeStats: 得到的信息是可读的字符串,比如
uxTaskGetSystemState:获得任务的统计信息
c
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
uint32_t * const pulTotalRunTime );
参数 | 描述 |
---|---|
pxTaskStatusArray | 指向一个TaskStatus_t结构体数组,用来保存任务的统计信息。 有多少个任务?可以用 uxTaskGetNumberOfTasks() 来获得。 |
uxArraySize | 数组大小、数组项个数,必须大于或等于uxTaskGetNumberOfTasks() |
pulTotalRunTime | 用来保存当前总的运行时间(更快的定时器),可以传入NULL |
返回值 | 传入的pxTaskStatusArray数组,被设置了几个数组项。 注意:如果传入的uxArraySize小于 uxTaskGetNumberOfTasks() ,返回值就是0 vTaskList :获得任务的统计信息,形式为可读的字符串。注意,pcWriteBuffer必须足够大。 |
- vTaskList :获得任务的统计信息,形式为可读的字符串。注意,pcWriteBuffer必须足够大。
c
void vTaskList( signed char *pcWriteBuffer );
可读信息格式如下:
- vTaskGetRunTimeStats:获得任务的运行信息,形式为可读的字符串。注意,pcWriteBuffer必须足够大。
c
void vTaskGetRunTimeStats( signed char *pcWriteBuffer );
可读信息格式如下: