1. 程式人生 > >使用FreeRTOS進行效能和執行時分析

使用FreeRTOS進行效能和執行時分析

在MCU on Eclipse網站上看到Erich Styger在2月25日發的博文,一篇關於使用FreeRTOS進行效能和執行分析的文章,本人覺得很有啟發,特將其翻譯過來以備參考。當然限於個人水平,有描述不當之處懇請指正。原文網址:https://mcuoneclipse.com/2018/02/25/performance-and-runtime-analysis-with-freertos/#more-23229

FreeRTOS作業系統的優點之一是它提供了免費的效能分析:它向我們展示在每個任務中花費了多少時間。最好的是:它在Eclipse中也以圖形的方式顯示了相應內容:

                                                                                Eclipse中的FreeRTOS執行時資訊

在上面的輸出中,我看到我的應用程式現在是97.5%的空閒,這是一件好事,符合我的期望,因為這個機器人正等待著在軌道上執行。

如何獲得這樣的資訊?

在Eclipse中的圖形檢視中需要一個Eclipse外掛(請參閱Eclipse中更好的FreeRTOS除錯)。該外掛已經預先安裝在NXP MCUXpresso IDE中。

另一種檢視該資訊的方法是使用“tasklist”命令,該命令將輸出傳送到控制檯(Segger RTT, UART, USB或類似的):

                                                                                  Tasklist命令

此命令可用於GitHub上的McuOnEclipse FreeRTOS。

如何工作的?

在每個任務切換時,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,使用手臂皮層迴圈計數器是另一種選擇,因為它不需要任何定時器或中斷。

歡迎關注: