How can I find real-time stack utilization of the FreeRTOS tasks?

Can anyone please suggest a way to find the real-time stack utilization of all the tasks created using FreeRTOS. I am able to track the maximum utilization by traversing the stack until the initialized value of the stack changes (Using functions like usStackHighWaterMark/prvTaskCheckFreeStackSpace/vTaskGetInfo/vTaskGetRunTimeStats, etc) - but this gives only the maximum stack used and not the real-time usage.
I’m guessing tracking the stack pointer could help to track to stack usage (However the ‘pxTopOfStack’ of the TCB seems to track the stack only when the task is initialized and doesn’t update continuously during the entire run-time of the task).
Can anyone please suggest a way to achieve this?

That is right and you should be able to read SP using assembly instruction. What are you trying to achieve with that?

Thanks for the quick reply.
I have a bunch of tasks that I created using the FreeRTOS functions. I want to track the stack usage of each task in real-time and build a utility to track it for optimization and debugging purposes. Could you please explain more on how I can read the stack pointer of each FreeRTOS task using assembly instruction?

It depends on the compiler and hardware you are using. For example, if you are using GCC compiler and Cortex-M MCU, this is how you will do it -

uint32_t stackPointer;
__asm volatile ( "mrs %0, msp" : "=r" ( stackPointer ) );

Just FYI - If you want to optimize stack size, all you need to know is the maximum stack usage.

I will point out the pxTopOfStack IS the current stack pointer for every task but the currently running one (or ones for a SMP port) In that case it will be the Stack Pointer when the task last was scheduled.

You can use the code presented to get your own stack pointer, but I don’t know of any portable way to get the stack pointer out of a parallel running processor (that answer is sort of obsolete before you even get it).

FreeRTOS doesnt manage the stack pointer during execution, except when switching between tasks - it saves the current SP for the task being swapped out and restores the SP for the task being swapped in. For its own purposes this is about as much as it needs to do, hence why that is the maximum visibility you have out of the box.

Otherwise the stack is essentially managed by the compiler through the instructions it generates.

Function calls may cause return addresses and parameters to be pushed onto the stack, and then those functions may utilise the stack to varying degrees for their own purposes. Tracking that in real time is going to be difficult, especially across 3rd party code/libraries.

Is there something about knowing the maximum stack usage that isnt enough for managing your stack sizes?