Memory analysis - 2023 edition #1569
Replies: 2 comments
-
I've finally had the time to make some progress on this topic. Monitoring of the memory usage:FreeRTOS provides a few functions that return the current heap usage and the all time highest heap usage. InfiniSimUsing a unique heap from FreeRTOS should also help InfiniSim more accurate regarding memory usage : InfiniSim would be constrained with the same amount of memory than the PineTime (as opposed to now, where InfiniSim can use all the memory from the host computer). Testing right nowI implemented the unique heap in InfiniTime and I'm currently testing it. Here's a summary of the changes: In
In
In
In
In the SystemInfo App:
What's next ?I'll test those changes in the next few days to see how it behaves. I'll use the casio watchface as this is the one that use the most memory (for the font). I would also like to see how we could use the information during development to check for stack overflow/failed allocation, and integrate those changes in InfiniSim. |
Beta Was this translation helpful? Give feedback.
-
Using the linker to override According to the documentation, we have to override void* malloc(size_t size);
void free(void* ptr);
void* calloc(size_t num, size_t size);
void* realloc( void *ptr, size_t newSize): At first, I was tempted to return NULL in
FreeRTOS does not provide a function that maps to void* realloc( void *ptr, size_t newSize) {
(void)(newSize);
uint8_t* bytePtr = ptr;
uint8_t* memory = pvPortMalloc(newSize);
if(memory == NULL) {
return NULL;
}
// This memcpy does InvalidReads because it reads outside of the memory allocated to ptr.
memcpy(memory, bytePtr, newSize);
vPortFree(ptr);
return memory;
} This is fine... but not completely : if newSize is greater than the older size, the call to The other option consists in implementing our own memory manager (based on heap_4.c that implements a Here's what an implement of
|
Beta Was this translation helpful? Give feedback.
-
This post is a follow-up and an update to the previous memory analysis done back in 2020.
I'll focus on RAM usage (static allocation, heap and stack).
The goals of this new analysis are
Current RAM usage
I took those measurement on tag 1.11.0 built with GCC 10:
Build info returned by the linker:
Build info by
arm-none-eabi-size
:With more details:
Static allocation
The total available RAM is 65536B (64KB).
arm-none-eabi-size
and linker do not take "global" stack (1024B) and heap (4096) into account.Which mean that the reported "% used" might be a fix confusing : they assume that the whole 64KB are available for static allocation, which is not true. The memory available for allocation in in fact
65536B - 1024B - 4096B = **60416B**
.InfiniTime 1.11 uses 940B in section
.data
(initialized RAM variables) and 53416B in.bss
(uninitialized variables). The total is 54356B.--> From this, we can conclude that we currently have
60416B - 54356B = 6060B
that are not allocated and that are available for future use.Details per module (static RAM usage, does not take stack + heap into account):
Heaps
InfiniTime allocates 3 heaps of memory. Those heaps are used for dynamic memory allocation at runtime.
malloc()
andnew()
allocate memory from this heap.What's using
malloc()
andnew()
?std::string
(they should really be replaced byconst char *
).std::unique_ptr
.FileOpen()
: 16B for each callNOTE : from those numbers, we can easily see that NimBLE allocates memory for each BLE attribute. We must keep that in mind when designing new BLE APIs!
Heaps unification
I have this idea in mind for quite some time now : let's try to unify all those 3 heaps into a single one. This should have many advantages:
Using the FreeRTOS heap as our unique heap looks like a good idea to me. It is design with constrained embedded use-cases in mind and it provides tools to monitor and track the memory usage.
On the other side, the LVGL one is dedicated to LVGL and cannot easily be used by other software module, and the "global" heap does not provide any way that I know to limit and monitor its usage.
LVGL supports custom heaps so replacing the LVGL one with the FreeRTOS implementation shouldn't be an issue.
It should be quite easy to specify a custom memory allocator for
LoadApp()
so that apps and watchfaces are allocated on the FreeRTOS heap as well.Finally, Nimble and LittleFS call
malloc()
directly, and I couldn't find any way that would allow to easily switch to another memory heap allocator. I plan on checking multiple solutions (modify those library so they call our custom allocator, using the linker to replace calls tomalloc()
to a custom function,...).Beta Was this translation helpful? Give feedback.
All reactions