DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • The Impact of AI Agents on Modern Workflows
  • A Developer’s Guide to Multithreading and Swift Concurrency
  • Mastering AI Agents: How Agentic Design Patterns Make Agents Smarter
  • Deep Work for Site Reliability Engineers

Trending

  • DZone's Article Submission Guidelines
  • Medallion Architecture: Why You Need It and How To Implement It With ClickHouse
  • Event-Driven Architectures: Designing Scalable and Resilient Cloud Solutions
  • Docker Base Images Demystified: A Practical Guide

Performance and Runtime Analysis With FreeRTOS

Love using FreeRTOS? Love performance monitoring? Then take a look at how to configure both for your projects as well as the ARM Cortex Cycle Counter.

By 
Erich Styger user avatar
Erich Styger
·
Feb. 28, 18 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
12.0K Views

Join the DZone community and get the full member experience.

Join For Free

One of the great things about the FreeRTOS operating system is that it comes with free performance analysis: It shows me how much time is spent on each task. Best of all: It shows it in a graphical way inside Eclipse, too:

FreeRTOS Runtime Information in Eclipse

FreeRTOS runtime information in Eclipse

In the above output, I see that my application is now 97.5% idle, which is a good thing and matches my expectations — as this robot is just waiting to run on a track.

How to Get That Kind of Information

For the graphical view in Eclipse, I need an Eclipse plugin (see Better FreeRTOS Debugging in Eclipse). That plugin is already pre-installed in the NXP MCUXpresso IDE.

Another way to see that information is using the ‘tasklist’ command, which sends the output to a console (Segger RTT, UART, USB or similar):

tasklist command

tasklist command

This command is available on the McuOnEclipse FreeRTOS available on GitHub.

How Does it Work?

FreeRTOS records, at the time of every task switch, how much time has been passed (or consumed) by that task switched out. For this, it uses a 32-bit counter inside the task information structure. This is actually the counter shown by the ‘tasklist’ command under the ‘Runtime’ column. The percentage is then calculated based on the numbers, which sum up as the total runtime.

The counter value inside FreeRTOS is a 32-bit value, so it is not really well-suited for very long measurement periods.

In order to collect these numbers, two FreeRTOS configuration defines have to be set to 1 in FreeRTOSConfig.h:

#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 */


The two above configuration items have a graphical setting if using Processor Expert:

Processor Expert Settings for Performance Analysis

Processor Expert settings for performance analysis

Counter

As mentioned above: FreeRTOS keeps track of the time spent for each task. But this is actually not the real time, it is just some kind of timer counter value if config GENERATE_RUN_TIME_STATS is turned on. In that case, the FreeRTOSConfig.h needs two configuration macros with the two application functions provided:

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() AppConfigureTimerForRuntimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE()         AppGetRuntimeCounterValueFromISR()


The first one is to configure the timer at RTOS startup, the second one is to return the actual timer counter value.

The general rule of thumb is that the timer used for measuring the task should be around 10x faster than the real tick counter for good results.

Users of Processor Expert have yet another advantage: They can easily configure such a timer in the Processor Expert setting, and everything is taken care of:

Processor Expert Timer for FreeRTOS

Processor Expert timer for FreeRTOS

Below is the setting for a timer that runs 10 times faster than the 1 kHz RTOS tick timer:

Performance Counter

Performance counter

Below is the resulting timer code:

/*
** ===================================================================
**     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
}


The interrupt service routine counts up a timer counter, which then is used to measure the time spent inside a task.

If interrupts are a concern from a performance point of view and no high precision is needed, then the Processor Expert port again has a nice feature: instead of using a dedicated timer, it simply re-uses the tick timer of the RTOS. For this, there is an extra setting to configure it:

#define configGENERATE_RUN_TIME_STATS_USE_TICKS 0 /* 1: Use the RTOS tick counter as runtime counter. 0: use extra timer */


The corresponding setting is the following in the UI:

Using Tick Counter

Using Tick Counter

With this, some basic measuring can be done. But this is not suitable for measuring short task execution times. Say the RTOS tick timer is 1 ms — then tasks running for less than 1 ms will be rarely measured.

Using ARM Cortex Cycle Counter

Another way to measure task execution time on ARM Cortex M (e.g. ARM Cortex-M4 or M7) is to use the Cortex Cycle Counter.

#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;
}


That approach measures the cycle counter difference between two calls to AppGetRuntimeCounterValueFromISR() and counts up a counter based on that value. In order not to count up too fast, the counter value is scaled down with a shift by 12 bits in above implementation (using a 120 MHz ARM Cortex-M4). For faster or slower running cores you might need to tweak that value.

Summary

FreeRTOS has built-in functions to track task execution time. It is implemented with a counter inside each task descriptor so does not need much RAM. The application has to provide a counter which is typically 10x faster than the tick time to get some reasonable measurements. But even using the tick counter itself gives some rough performance analysis data. Otherwise, the application can offer a periodic timer counter. If using an ARM Cortex-M3/M4/M7, using the ARM Cortex Cycle counter is an alternative, as it does not need any timer or interrupts.

Happy performing!

Links

  • MCUXpresso IDE web page: http://www.nxp.com/mcuxpresso/ide
  • MCUXpresso IDE community: http://www.nxp.com/mcuxpresso/ide/forum
  • Better FreeRTOS Debugging in Eclipse
  • McuOnEclipse Library project: https://github.com/ErichStyger/McuOnEclipseLibrary/tree/master/lib/FreeRTOS/Source
  • ARM Cortex-M Cycle Counter: https://mcuoneclipse.com/2017/01/30/cycle-counting-on-arm-cortex-m-with-dwt/
FreeRTOS Task (computing)

Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • The Impact of AI Agents on Modern Workflows
  • A Developer’s Guide to Multithreading and Swift Concurrency
  • Mastering AI Agents: How Agentic Design Patterns Make Agents Smarter
  • Deep Work for Site Reliability Engineers

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: