FreeRTOS performance counters implemented in the ARM Cortex-M

  Description: This translation from Erich Styger article "Implementing FreeRTOS Performance Counters on ARM Cortexthe ownership belongs to the original author of the article.

  When RTOS such as FreeRTOS, sooner or later have to ask the question: how much time each task takes? It has a good view of the Eclipse-based MCUXpresso IDE, shows exactly this information:

 

FreeRTOS runtime information

  To make FreeRTOS (or "Task List" view) displays useful information, developers must provide assistance so that this information can be collected RTOS. This article shows how to do this on the ARM Cortex-M.

1 , Overview

  Not long ago, I discussed the topic of performance analysis and run FreeRTOS time from the perspective of the processor experts. This is about the use of "native" FreeRTOS and use NXP MCUXpresso SDK, but the same principles will apply to all Cortex-M processor and other environmental microcontroller. As FreeRTOS port, I am using the port https://github.com/ErichStyger/McuOnEclipseLibrary, because the port is already all the necessary hooks. Provide all the documents and sources used in this article on GitHub.

2 , How It Works

  The operating system uses a counter to measure the task execution time. Thus, the task context switch time, this counter is used to determine the time used by the task. The important point is, that the time is not absolute (e.g. 37 ms), but the number of "ticks" (e.g., 241 ticks). RTOS aware of how many "clicks" on the whole. RTOS know how many tasks in the system there, so it can display each task takes a percentage of the total time. Another thing to note is that time * * including time spent in interrupt.

  This is a very simple yet powerful method of estimating task execution time is usually what you need. It can be implemented in a very simple way: incrementing a counter using a timer and a function for reading the counter value.

  To turn on performance measurement, I have to enable two FreeRTOS configuration settings:

1 #define configUSE_TRACE_FACILITY 1 /* 1: include additional structure members and functions to assist with execution visualization and tracing, 0: no runtime stats/trace */
2 
3 #define configGENERATE_RUN_TIME_STATS 1 /* 1: generate runtime statistics; 0: no runtime statistics */

  To configure the timer and counter read, I have to use two macros to tell the function name:

1 #define configGET_RUNTIMER_COUNTER_VALUE_FROM_ISR   AppGetRuntimeCounterValueFromISR
2 
3 #define configCONFIGURE_TIMER_FOR_RUNTIME_STATS     AppConfigureTimerForRuntimeStats

3 , using a "tick" counter

  A very simple method to measure the implementation of the mandate is to use FreeRTOS tick counter itself. You can enable the following ways

1 #define configGENERATE_RUN_TIME_STATS_USE_TICKS     (1)

  However, this can only measure the task execution time when the task execution time exceeds the RTOS tick cycle. For faster task, this method does not work. The Nyquist-Shannon sampling theorem, I preferred to use 2-fold (better: 10 times) of the measurement frequency.

4 , using Cortex-M period counter

  Another way to achieve this is to use a counter Cortex-M period counter, which has been implemented in many devices, and gives good results. Best of all: no disruption or additional timer. Possible implementation is as follows:

 1 static uint32_t prevCycleCounter, cycleCntCounter = 0;
 2  
 3 void AppConfigureTimerForRuntimeStats(void) {
 4   cycleCntCounter = 0;
 5   McuArmTools_InitCycleCounter();
 6   prevCycleCounter = McuArmTools_GetCycleCounter();
 7 }
 8  
 9 uint32_t AppGetRuntimeCounterValueFromISR(void) {
10   uint32_t newCntr, diff;
11  
12   newCntr = McuArmTools_GetCycleCounter();
13   diff = newCntr-prevCycleCounter;
14   prevCycleCounter = newCntr;
15   cycleCntCounter += diff>>12; /* scale down the counter */
16   return cycleCntCounter;
17 }

5、使用定期定时器中断

 

  标准方法是使用定期中断计时器,该计时器增加计数器。对于1 kHz滴答计时器,推荐的频率是FreeRTOS滴答计时器频率的10倍,在这种情况下为10 kHz(100 us):

 1 static uint32_t perfCounter = 0;
 2  
 3 #define PIT_BASEADDR       PIT
 4 #define PIT_SOURCE_CLOCK   CLOCK_GetFreq(kCLOCK_BusClk)
 5 #define PIT_CHANNEL        kPIT_Chnl_0
 6 #define PIT_HANDLER        PIT0_IRQHandler
 7 #define PIT_IRQ_ID         PIT0_IRQn
 8  
 9 void PIT_HANDLER(void) {
10   PIT_ClearStatusFlags(PIT_BASEADDR, PIT_CHANNEL, kPIT_TimerFlag);
11   perfCounter++;
12   __DSB();
13 }
14  
15 void AppConfigureTimerForRuntimeStats(void) {
16   pit_config_t config;
17  
18   PIT_GetDefaultConfig(&config);
19   config.enableRunInDebug = false;
20   PIT_Init(PIT_BASEADDR, &config);
21   PIT_SetTimerPeriod(PIT_BASEADDR, PIT_CHANNEL, USEC_TO_COUNT(100U, PIT_SOURCE_CLOCK));
22   PIT_EnableInterrupts(PIT_BASEADDR, PIT_CHANNEL, kPIT_TimerInterruptEnable);
23   NVIC_SetPriority(PIT_IRQ_ID, 0);
24   EnableIRQ(PIT_IRQ_ID);
25   PIT_StartTimer(PIT_BASEADDR, PIT_CHANNEL);
26 }
27  
28 uint32_t AppGetRuntimeCounterValueFromISR(void) {
29   return perfCounter;
30 }

6、摘要

 

  FreeRTOS包含一项功能,可以测量相对于系统中其他任务的任务执行时间。我需要提供的是计时器或某种计数器的初始化例程,以及获取计数器值的方法。如果您对检查FreeRTOS计时的其他方式感兴趣,请查看Percepio Tracealyzer或Segger SystemView。如果您希望应用程序本身显示性能数据,请查看“ 使用FreeRTOS进行性能和运行时分析”中介绍的Shell / Commandline实现。

7、链接

欢迎关注:

Guess you like

Origin www.cnblogs.com/foxclever/p/12151472.html