說明:本文翻譯自Erich Styger的文章《Implementing FreeRTOS Performance Counters on ARM Cortex-M》,文章的權屬屬於原作者。
當使用像FreeRTOS這樣的RTOS時,遲早要問一個問題:每個任務花費多少時間?基於Eclipse的MCUXpresso IDE具有很好的視圖,準確顯示了此類信息:
FreeRTOS運行時信息
爲了使FreeRTOS(或“任務列表”視圖)顯示非常有用的信息,開發人員必須提供幫助,以便RTOS可以收集此信息。本文說明如何在ARM Cortex-M上完成此操作。
1、概述
不久前,我從處理器專家的角度討論了FreeRTOS的性能和運行時分析中的該主題。這次是關於使用“本機” FreeRTOS和使用NXP MCUXpresso SDK,但是相同的原理將適用於Cortex-M處理器和微控制器的所有其他環境。至於FreeRTOS端口,我正在使用https://github.com/ErichStyger/McuOnEclipseLibrary中的端口,因爲該端口已經存在所有需要的鉤子。GitHub上提供了本文中使用的所有文件和源。
2、如何工作
操作系統使用計數器來衡量任務執行時間。因此,在任務上下文切換時間,此計數器用於確定該任務使用的時間。重要的一點是,該時間不是絕對的(例如37毫秒),而是一些“滴答聲”(例如241個滴答聲)。RTOS知道總體上使用了多少“滴答聲”。RTOS知道系統中有多少個任務,因此它可以顯示每個任務花費了總時間的百分比。另一個要注意的是,時間*包括*在中斷中花費的時間。
這是一種非常簡單但功能強大的估算任務執行時間的方法,通常就是您所需要的。它可以通過一種非常簡單的方式來實現:使用一個使計數器遞增的計時器和一個用於讀取計數器值的函數。
要打開性能測量,我必須啓用兩個FreeRTOS配置設置:
#define configUSE_TRACE_FACILITY 1 /* 1: include additional structure members and functions to assist with execution visualization and tracing, 0: no runtime stats/trace */
#define configGENERATE_RUN_TIME_STATS 1 /* 1: generate runtime statistics; 0: no runtime statistics */
要配置計時器並讀取計數器,我必須使用兩個宏來告訴函數名稱:
#define configGET_RUNTIMER_COUNTER_VALUE_FROM_ISR AppGetRuntimeCounterValueFromISR
#define configCONFIGURE_TIMER_FOR_RUNTIME_STATS AppConfigureTimerForRuntimeStats
3、使用“滴答”計數器
一種非常簡單的衡量任務執行情況的方法是使用FreeRTOS滴答計數器本身。可以通過以下方式啓用
#define configGENERATE_RUN_TIME_STATS_USE_TICKS (1)
但是,這僅在任務執行時間超過RTOS滴答週期時才能測量任務執行時間。對於更快的任務,此方法沒有用。根據Nyquist-Shannon採樣定理,我最好使用2倍(更好:10倍)的測量頻率。
4、使用Cortex-M週期計數器
實現該計數器的另一種方法是使用Cortex-M週期計數器,該計數器已在許多設備上實現,並給出了很好的結果。最好的是:無需中斷或額外的計時器。可能的實現如下所示:
static uint32_t prevCycleCounter, cycleCntCounter = 0;
void AppConfigureTimerForRuntimeStats(void) {
cycleCntCounter = 0;
McuArmTools_InitCycleCounter();
prevCycleCounter = McuArmTools_GetCycleCounter();
}
uint32_t AppGetRuntimeCounterValueFromISR(void) {
uint32_t newCntr, diff;
newCntr = McuArmTools_GetCycleCounter();
diff = newCntr-prevCycleCounter;
prevCycleCounter = newCntr;
cycleCntCounter += diff>>12; /* scale down the counter */
return cycleCntCounter;
}
5、使用定期定時器中斷
標準方法是使用定期中斷計時器,該計時器增加計數器。對於1 kHz滴答計時器,推薦的頻率是FreeRTOS滴答計時器頻率的10倍,在這種情況下爲10 kHz(100 us):
static uint32_t perfCounter = 0;
#define PIT_BASEADDR PIT
#define PIT_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_BusClk)
#define PIT_CHANNEL kPIT_Chnl_0
#define PIT_HANDLER PIT0_IRQHandler
#define PIT_IRQ_ID PIT0_IRQn
void PIT_HANDLER(void) {
PIT_ClearStatusFlags(PIT_BASEADDR, PIT_CHANNEL, kPIT_TimerFlag);
perfCounter++;
__DSB();
}
void AppConfigureTimerForRuntimeStats(void) {
pit_config_t config;
PIT_GetDefaultConfig(&config);
config.enableRunInDebug = false;
PIT_Init(PIT_BASEADDR, &config);
PIT_SetTimerPeriod(PIT_BASEADDR, PIT_CHANNEL, USEC_TO_COUNT(100U, PIT_SOURCE_CLOCK));
PIT_EnableInterrupts(PIT_BASEADDR, PIT_CHANNEL, kPIT_TimerInterruptEnable);
NVIC_SetPriority(PIT_IRQ_ID, 0);
EnableIRQ(PIT_IRQ_ID);
PIT_StartTimer(PIT_BASEADDR, PIT_CHANNEL);
}
uint32_t AppGetRuntimeCounterValueFromISR(void) {
return perfCounter;
}
6、摘要
FreeRTOS包含一項功能,可以測量相對於系統中其他任務的任務執行時間。我需要提供的是計時器或某種計數器的初始化例程,以及獲取計數器值的方法。如果您對檢查FreeRTOS計時的其他方式感興趣,請查看Percepio Tracealyzer或Segger SystemView。如果您希望應用程序本身顯示性能數據,請查看“ 使用FreeRTOS進行性能和運行時分析”中介紹的Shell / Commandline實現。
7、鏈接
- GitHub上的項目:https : //github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/tinyK22/tinyK22_FreeRTOS
- FreeRTOS的性能和運行時分析
- 在Eclipse中更好的FreeRTOS調試
- ARM SWO性能計數器
- GitHub上的McuLib:https : //github.com/ErichStyger/McuOnEclipseLibrary
- MCUXpresso IDE和SDK:https ://mcuxpresso.nxp.com