Measuring Memory on your Spark

Hi,

i’ve had a hard time finding my way to do complex things with the Spark, cause of the very limited amount of memory.

I want to share my findings with you.

There a two types of dynamical Memory (HEAP and Stack). The Heap starts on the bottom of the available memory (and gos up), the Stack starts from the Top (and goes down).

If these two borders come close to each other, and cross -> this is your “out of memory SOS Blink”

If you are not using dynamic allocation, some libarys and the Core connection will do.

The Stack, on the other side, contains any local variable (inside a function). So every function call (which calls other functions) are filling the stack. If the function ends, the stack will be freed automaticly.

The following function will measure the distance in Bytes between these two borders.

extern "C" char *sbrk(int i);
uint32_t freeMemoryAvailable(void)
{
    register char * current_stack_pointer asm ("sp");  
    char *heapend=sbrk(0);
    return  (current_stack_pointer - heapend);
}

In our SparkSystem (including cloud connection httpclient etc.) we are not able to call Cloud functions if this value is below 3000 bytes.

if you have a long running system, you can also publish these values as an Event.

Are there any other tricks to measure memory during runtime?

2 Likes

As it happens the implementation of sbrk(), malloc() and realloc() don’t seem to update the (heap) _end variable propperly so, even when allocating memory the free mem doesn’t seem to change.

I’ve tested this with this code


void** ptr = NULL;

extern "C" char *sbrk(int i);
uint32_t freeMemoryAvailable(void)
{
	register char* current_stack_pointer asm ("sp");  
	char* heapend= sbrk(0);
    return  (current_stack_pointer - heapend);
}

void setup()
{
    Spark.function("test", fnTest);
    Spark.function("freeAll", fnFree);
}

void loop()
{

}

int fnTest(String cmd)
{
    // this will hard fault after aprox 10 calls 
    // unless fnFree() is called in beteween
    void** oldPtr = ptr;
    ptr = (void**)malloc(1000);
    *ptr = oldPtr;
    
    return freeMemoryAvailable();
}

int fnFree(String cmd)
{
    void** prevPtr;
    
    while (ptr != NULL)
    {
        prevPtr = (void**)*ptr;
        free(ptr);
        ptr = prevPtr;
    }
    
    return freeMemoryAvailable();
}

I was trying to have a look at the implementation of malloc(), but couldn’t find it.
Maybe @mdma would like to jump in here :wink:
I’ve also tried src/newlib_stubs.cpp _sbrk(), but this doesn’t update _end either.

Yep. I also tried the use malloc, but this doesn’t work well (over time).

Maybe these functions are not complety implemented.

I’ve also tried including malloc.h

struct mallinfo stc = mallinfo();
		Serial.println("[arena "+String(stc.arena)+"]");
		Serial.println("[ordblks "+String(stc.ordblks)+"]");
		Serial.println("[smblks "+String(stc.smblks)+"]");
		Serial.println("[hblks "+String(stc.hblks)+"]");
		Serial.println("[hblkhd "+String(stc.hblkhd)+"]");
		Serial.println("[usmblks "+String(stc.usmblks)+"]");
		Serial.println("[fsmblks "+String(stc.fsmblks)+"]");
		Serial.println("[uordblks "+String(stc.uordblks)+"]");
		Serial.println("[fordblks "+String(stc.fordblks)+"]");
		Serial.println("[keepcost "+String(stc.keepcost)+"]");

The results are also not meaningfull

Sadly :anguished:

Especially in connection with the String discussion in the other thread, some more info how the heap gets used (and fragmented) would become handy.
I guess there must be a dynamic memory map of the heap and if this was accessible this would provide some way to defrag the heap and reduce panic faults.

_end is the bottom of the reserved region of the stack - or the top of the area reserved for the heap. It's static, and so doesn't change. heap_end points to the current top of the heap, but this isn't any indication of how much free memory there is.

To find that out, you have to walk the linked list of allocated regions.

malloc() implementation is part of glibc - sources are at http://fossies.org/dox/glibc-2.20/malloc_8c_source.html but I can't guarantee this is the same as used on the arm platform.

4 Likes

I think, at the end, the heap is not the problem (especially the amount of heap left). Cause the main question is the amount of Stack the system needs (especially during calls and housekeeping from the background cloud connection) at any time!
Therefor sometimes even 4000bytes memory left is not enough to (re)establish a connection to the cloud.