Added Heap Memory Monitoring and Tracking to FreeRTOS V10.5

We all should know it: dynamic memory usage can be dangerous. There can be memory fragmentation, use-after-free, out-of-memory and memory leaks. While I do prefer static memory allocation for embedded systems, using a dynamic memory allocation in some applications is not avoidable or just makes sense.

In one of my lecture modules we develop a ‘Boulder’ game, where the player has to collect underground diamonds and avoid moving monsters:

LPC845-BRK with OLED using dynamic memory allocation

I’ll show you have FreeRTOS memory usage can be tracked and monitored.

Outline

The game uses lots of animated and moving ‘sprites’ which get dynamically created and destroyed. The game is used to teach many aspects of embedded systems (interrupts, reentrancy, threads, semaphore, mutex, events, …) and runs with FreeRTOS:

Game on OLED Display

One challenge with such a dynamic application is a correct memory management. In this article I show you how FreeRTOS can be instrumented to monitor Heap events with SystemView:

Heap Event Monitoring with FreeRTOS and Segger SystemView

Eclipse Heap View

Students already can see and monitor the heap memory usage in Eclipse using the NXP MCUXpresso IDE:

Eclipse Heap Memory View (FreeRTOS)

But this only shows the current state of the allocated blocks, in a ‘static’ way. What we need is who allocated the block, and when it was released. We can get this with SystemView, with the help of an extended and instrumented FreeRTOS.

SystemView

Students use as well the Segger SystemView to record and monitor the task execution. When I downloaded and installed the latest Version v3.50a, I noticed a new ‘Heap’ view in it:

Heap in SEGGER SystemView

There is some documentation about this new view, and the API documentation is very minimal. And there is no guidance how to use it for example with FreeRTOS. Over this long weekend I decided to upgrade to FreeRTOS 202212.01 (V10.5.1) and to implement heap memory monitoring.

FreeRTOS V10.5.1 and SystemView V3.50a

Using SystemView requires patching FreeRTOS to use the SystemView hooks for heap monitoring and heap event generation. I have updated both the McuLib and Processor Expert ports (see links at the end of the article).

The events are turned on by default, but can be turned off with a configuration setting:

#define configUSE_SEGGER_SYSTEM_VIEWER_HEAP_EVENTS  (0) /* 0: disabled heap events */

To have SystemView recording and monitoring the heap events, we need to instrument the application. I have instrumented and extended the FreeRTOS Kernel to keep track of all heap events, included the ones from the kernel.

Register Heap

The heap needs to be registered first. You can register any number of heaps. Below is the FreeRTOS heap implementation which calls SEGGER_SYSVIEW_HeapDefine():

#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
  SEGGER_SYSVIEW_HeapDefine(ucHeap, ucHeap, sizeof(ucHeap), sizeof(BlockLink_t));
#endif

The first parameter is a ‘heap identifier’, followed by a pointer to the memory itself, the size and the internal memory block overhead. That overhead is used to calculate the free and used space of the heap. This creates a ‘Define Heap’ event:

Define Heap Event

💡 Attentive readers will notice the wrong detail message. This already has been reported to Segger, so I expect this to be fixed in a next version of SystemView.

The recorded event is shown as well in the ‘Heap’ view:

Heap View with ‘Define Heap’ event

With this, the SystemView knows about the heap and its size, and it can be tracked. Note that it is possible to have multiple heaps defined.

Resource ID

To have a name for the heap, I can set a name for a resource, using SEGGER_SYSVIEW_NameResource():

#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS /* << EST */
  SEGGER_SYSVIEW_HeapDefine(ucHeap, ucHeap, sizeof(ucHeap), sizeof(BlockLink_t));
  SEGGER_SYSVIEW_NameResource((uint32_t)ucHeap, "heap4");
#endif

With this, the resource shows up with a symbolic name:

Named Resource

Memory Allocation

Each block or memory allocation is tracked with a call to SEGGER_SYSVIEW_HeapAlloc(): FreeRTOS-Trace defines the traceMALLOC() macro, but this one is not sufficient for the SystemView events.

#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
  SEGGER_SYSVIEW_HeapAlloc(ucHeap, pvReturn, xWantedSize);
#else
  traceMALLOC( pvReturn, xWantedSize );
#endif

This creates ‘Allocate Memory’ events which are shown in the event log:

Allocate Memory events

It knows about the context (e.g. task) where the allocation happens. The events are shown in the Heap view as below:

Memory Events in Heap view

The really cool thing is that I can filter for the events (unfortunately, I cannot sort the columns). It keeps track of the allocation, free and used sizes, including peak usage which is great.

Memory Free

In a similar way, freeing of memory is tracked with SEGGER_SYSVIEW_HeapFree():

#if configUSE_SEGGER_SYSTEM_VIEWER_HOOKS
  SEGGER_SYSVIEW_HeapFree(ucHeap, pv);
#else
  traceFREE( pv, pxLink->xBlockSize );
#endif

The event is shown in a similar way:

Free Memory Event

De-allocation events are shown with a non-solid red icon. Memory blocks which have been allocated and released later are shown with a non-solid green icon.

Allocate and Free Memory

Memory which is still allocated is displayed with a solid green icon:

Still allocated memory blocks

This makes it really easy to spot memory leaks in the Heap or general events view.

Tagging Memory

Another useful feature is the ability to tag the memory. Basically I can assign a number to a memory block which then can be used for filtering:

Tag for Memory Blocks

This is accomplished using the following which is part of the FreeRTOS pvPortMallocExt():

void SEGGER_SYSVIEW_HeapAllocEx(void* pHeap, void* pUserData, unsigned int UserDataLen, unsigned int Tag);

For example I can use a list of different memory types as an enumeration:

typedef enum SYSVIEW_HeapTag_e {
  SYSVIEW_HEAP_TAG_TIMAGE,
  SYSVIEW_HEAP_TAG_IMAGE,
  SYSVIEW_HEAP_TAG_PIXELS,
  SYSVIEW_HEAP_TAG_SPRITE,
  SYSVIEW_HEAP_TAG_SPRITE_IMAGE,
} SYSVIEW_HeapTag_e;

And then use the tag with pvPortMallocExt():

SpriteImage_t *Sprite_NewImageFromROM(const PIMAGE image) {
  SpriteImage_t *p;
  PIMAGE i;

  /* create new sprite image */
  p = pvPortMallocExt(sizeof(SpriteImage_t), SYSVIEW_HEAP_TAG_SPRITE_IMAGE);
  assert(p!=NULL);
  /* create the image in RAM. PIMAGE is pointing to ROM data */
  i = pvPortMallocExt(sizeof(TIMAGE), SYSVIEW_HEAP_TAG_TIMAGE);
  assert(i!=NULL);
  i->pixmap = pvPortMallocExt(image->size, SYSVIEW_HEAP_TAG_IMAGE);
  assert(i->pixmap!=NULL);
  memcpy((void*)i->pixmap, image->pixmap, image->size);
  i->size = image->size;
  i->height = image->height;
  i->width = image->width;
  i->name = NULL; /* don't care */
  p->image = i;
  p->next = p; /* circular */
  p->prev = p; /* circular */
  return p;
}

With this, the different blocks are tagged and I can filter them:

Filter on Tag

Summary

Dynamic memory usage can be challenging, but it is now easy to instrument FreeRTOS to report memory events and have it visualized in SystemView. That makes it easy to track who is allocating memory, and if it is properly freed again. It is very helpful as well to get the peak memory usage, to adjust the heap memory allocated.

For this, I have extended the FreeRTOS port to take advantage of additional instrumentation, to keep track of memory allocation and de-allocation. The port and implementation for FreeRTOS 10.5.1 can be found on GitHub (see links below).

The API allows to track multiple heaps in parallel. For the moment it I have it implemented for the FreeRTOS heap versions. If time permits, I’ll have it extended to the C/C++ Standard Library too.

Happy memorizing 🙂

Links

Advertisement

9 thoughts on “Added Heap Memory Monitoring and Tracking to FreeRTOS V10.5

  1. Of course, in embedded, dynamic memory is a verboten which is one of the reasons why C++ isn’t used. OTOH, if you have to use it, this isn’t a bad setup so that a person can verify that you don’t have memory leaks.

    Like

    • Using C++ does not mean you are using dynamic memory by default. It all depends how and what you are using. For example using static classes is perfectly fine.
      In contrast, you might already use dynamic memory if using a printf() (depending on the library). So it is not necessarily the fault of the language, but what libraries are used.

      Like

      • True that. The problem is in one of paying attention. Lots of modern programmers don’t do that so it’s important to know exactly what your (and your libraries) code is doing. C++ is fine (even a good thing) as long as you know what the underlying things are doing and don’t do the things your used to as a desktop programmer.

        Like

  2. Graphical views of heap and custom data can in fact be useful.
    It’s on our list for Systemview.
    One of the nice things about Systemview is our friendly licensing.
    Free for educational and non commercial use. No hassles, download and go!
    And BTW: Thanks Erich, for giving our heap management a spin with this project
    and extending the FreeRTOS port.

    Liked by 1 person

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.