在MCU on Eclipse網站上看到Erich Styger在2月25日發的博文,一篇關於使用FreeRTOS進行性能和運行分析的文章,本人以爲頗有啓發,特將其翻譯過來以備參考。固然限於我的水平,有描述不當之處懇請指正。原文網址:https://mcuoneclipse.com/2018/02/25/performance-and-runtime-analysis-with-freertos/#more-23229eclipse
FreeRTOS操做系統的優勢之一是它提供了免費的性能分析:它向咱們展現在每一個任務中花費了多少時間。最好的是:它在Eclipse中也以圖形的方式顯示了相應內容:函數
Eclipse中的FreeRTOS運行時信息性能
在上面的輸出中,我看到個人應用程序如今是97.5%的空閒,這是一件好事,符合個人指望,由於這個機器人正等待着在軌道上運行。網站
如何得到這樣的信息?ui
在Eclipse中的圖形視圖中須要一個Eclipse插件(請參閱Eclipse中更好的FreeRTOS調試)。該插件已經預先安裝在NXP MCUXpresso IDE中。操作系統
另外一種查看該信息的方法是使用「tasklist」命令,該命令將輸出發送到控制檯(Segger RTT, UART, USB或相似的):插件
Tasklist命令翻譯
此命令可用於GitHub上的McuOnEclipse FreeRTOS。調試
如何工做的?component
在每一個任務切換時,FreeRTOS記錄會切換到該任務所傳遞的時間(或消耗的時間)。爲此,它在任務信息結構中使用了一個32位計數器。這其實是在「運行時」列下的「任務列表」命令顯示的計數器。而後根據總運行時的總數來計算百分比。
FreeRTOS內部的計數器值爲32位,因此它不太適合長時間的測量。
爲了修正這些數字,在FreeRTOSConfig.h中必須將兩個FreeRTOS配置定義爲1。
#define configUSE_TRACE_FACILITY 1 /* 1: 包括額外的結構成員和功能,以協助執行可視化和跟蹤,0: 沒有運行時狀態跟蹤*/
#define configGENERATE_RUN_TIME_STATS 1 /* 1: 生成運行時統計; 0: 沒有運行時統計 */
若是使用處理器專家,上述兩個配置項有一個圖形化設置:
用於性能分析的處理器專家設置
計數器
如上所述:FreeRTOS記錄了每一個任務所花費的時間。但這實際上不是實時的,若是configGENERATE_RUN_TIME_STATS打開,它只是某種計時器的計數器值。在這種狀況下,FreeRTOSConfig。h須要配置有兩個應用程序功能配置的宏:
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() AppConfigureTimerForRuntimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() AppGetRuntimeCounterValueFromISR()
第一個是在RTOS啓動時配置timer,第二個是返回實際的計時器計數器值。
通常的經驗法則是,用於測量任務的計時器應該比實際的滴答計數器快10倍。
處理器專家的用戶又有了一個優點:他們能夠在處理器專家設置中輕鬆地配置這樣的計時器,而且一切都獲得了處理:
FreeRTOS的處理器專家計時器
下面是一個計時器的設置,它的運行速度是1 kHz RTOS計時器的10倍。
性能計數器
下面是產生的定時器代碼:
/*
** ===================================================================
** Method : FRTOS1_OnCounterRestart (component FreeRTOS)
**
** Description :
** This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
void RTOSCNTRLDD1_OnCounterRestart(LDD_TUserData *UserDataPtr __attribute__((unused)))
{
FRTOS1_RunTimeCounter++; /* increment runtime counter */
}
/*
** ===================================================================
** Method : FRTOS1_AppConfigureTimerForRuntimeStats (component FreeRTOS)
** Description :
** Configures the timer for generating runtime statistics
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
#if configGENERATE_RUN_TIME_STATS
void FRTOS1_AppConfigureTimerForRuntimeStats(void)
{
#if configGENERATE_RUN_TIME_STATS_USE_TICKS
/* nothing needed, the RTOS will initialize the tick counter */
#else
FRTOS1_RunTimeCounter = 0;
FRTOS1_RunTimeCounterHandle = RTOSCNTRLDD1_Init(NULL);
(void)RTOSCNTRLDD1_Enable(FRTOS1_RunTimeCounterHandle);
#endif
}
#endif /* configGENERATE_RUN_TIME_STATS */
/*
** ===================================================================
** Method : FRTOS1_AppGetRuntimeCounterValueFromISR (component FreeRTOS)
** Description :
** returns the current runtime counter. Function can be called
** from an interrupt service routine.
** Parameters : None
** Returns :
** --- - runtime counter value
** ===================================================================
*/
uint32_t FRTOS1_AppGetRuntimeCounterValueFromISR(void)
{
#if configGENERATE_RUN_TIME_STATS
#if configGENERATE_RUN_TIME_STATS_USE_TICKS
return xTaskGetTickCountFromISR(); /* using RTOS tick counter */
#else /* using timer counter */
return FRTOS1_RunTimeCounter;
#endif
#else
return 0; /* dummy value */
#endif
}
中斷服務例程計數一個計時器計數器,該計數器用於度量在任務中花費的時間。
若是中斷是從性能角度考慮的問題,而且不須要很高的精度,那麼處理器專家端口就有一個很好的特性:它不使用專用計時器,而是從新使用RTOS的滴答計時器。爲此,有一個額外的設置來配置這個:
#define configGENERATE_RUN_TIME_STATS_USE_TICKS 0 /* 1: 使用RTOS tick計數器做爲運行時計數器。 0: 使用額外的
在UI中對應的設置以下:
使用Tick計數器
有了這些,咱們能夠作一些基本的測量。但這不適合測量短任務執行時間。說RTOS的計時器是1毫秒,那麼運行不到1毫秒的任務將不多被測量。
使用ARM Cortex循環計數器
另外一種在ARM Cortex M(例如:Cortex-M4或M7)上測量執行時間的方法是使用ARM Cortex循環計數器。
#include "KIN1.h"
static uint32_t prevCycleCounter, cycleCntCounter = 0;
void AppConfigureTimerForRuntimeStats(void) {
cycleCntCounter = 0;
KIN1_InitCycleCounter();
prevCycleCounter = KIN1_GetCycleCounter();
}
uint32_t AppGetRuntimeCounterValueFromISR(void) {
uint32_t newCntr, diff;
newCntr = KIN1_GetCycleCounter();
diff = newCntr-prevCycleCounter;
prevCycleCounter = newCntr;
cycleCntCounter += diff>>12; /* scale down the counter */
return cycleCntCounter;
}
這種方法測量循環計數器區別兩個調用AppGetRuntimeCounterValueFromISR()和基於價值的計數器計數。爲了避免過快地計算,計數器的值在上面的實現(使用120 MHz ARM的Cortex-M4)上按12位的偏移量縮小。對於運行速度更快或更慢的內核,您可能須要調整該值。
總結
FreeRTOS具備跟蹤任務執行時間的內置函數。它是在每一個任務描述符中使用一個計數器實現的,所以不須要太多RAM。應用程序必須提供一個計數器,其速度一般比正常狀況下要快10倍,以得到一些合理的測量值。可是,即便使用tick計數器自己也會給出一些粗略的性能分析數據。不然,應用程序能夠提供一個按期計時器計數器。若是使用臂皮質- m3 /M4/M7,使用手臂皮層循環計數器是另外一種選擇,由於它不須要任何定時器或中斷。
歡迎關注: