How to determine how much stack is used in a task

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to determine how much stack is used in a task

Jump to solution
6,150 Views
myke_predko
Senior Contributor III

As my project grows, I am finding that I am running out of memory for use in the stacks. 

I tried to take away stack space in tasks that seemed very simple, but that is turning into a hit or miss approach that takes a lot of time and even if it doesn't crash the system, I don't want to take away something that will be needed later. 

Is there anywhere I can look in the TAD options or any rules of thumb that I can use for specifying stack space for a task to ensure that I am using enough and no more? 

Thanx,

myke

1 Solution
3,470 Views
c0170
Senior Contributor III

Hello Myke Predko,

I believe TAD uses the stack monitor feature in MQX which calculates the stack usage based on a pattern (maximum stack usage, how far stack has gone down for each task). If an application enables the stack monitor, the entire stack is filled with the pattern. This can be used as a watermark, therefore open your memory window and run an application for a while to execute deepest calls. Then calculate how deep the stack usage has gone.

Pattern to watch in the memory window:

#define MQX_STACK_MONITOR_VALUE (_mqx_uint)(0x7374616B)

The name of the function which fills stack with the pattern located in _mqx function:

#if MQX_MONITOR_STACK

    _task_fill_stack_internal((_mqx_uint_ptr)stack_ptr, result);

#endif

You should end up approximately with same numbers as stack usage percentages in TAD plugin. This brings up the question if my assumptions about TAD were correct, how come your application faces stack corruptions. You can prove this with watching memory window, each stack has own size and a base address. Please verify each stack space in memory window after a reduction of stack sizes if there's still the defined pattern within its own space, that would prove there's no stack overflow.

There are some static methods which could help you to find out an application's deepest call. They usually need a help from a linker to be accurate (indirect calls), like in KEIL there's callgraph and IAR has own plugin stack.

Regards,

c0170

View solution in original post

6 Replies
3,470 Views
c0170
Senior Contributor III

Hello Myke Predko,

TAD provides the Stack usage feature where you can see how much stack is being used. Another available choice is to use klog (source/io/klog.c). Following functions are defined in the code file:

_klog_get_task_stack_usage

_klog_get_interrupt_stack_usage

_klog_show_stack_usage

To use them, an application must enable kernel logging (MQX_KERNEL_LOGGING) and enable monitor stack monitoring (MQX_MONITOR_STACK). Please refer to the source code for more information and MQX RM.

Let us know which one fits your needs and share the result with us! :smileywink:

Regards,

c0170

3,470 Views
myke_predko
Senior Contributor III

Hi Martin,

Sorry, I should have been more specific in saying that I was aware of looking at the stack usage from MQX - the problem with these methods is that they show current use, not the maximum. 

When I follow these values and reduce them what seems appropriate I find problems during execution.  For example, if in a task, I see that it is using 21% of the stack available I feel that I should be able to reduce it's stack safely by 50% - BUT, it seems like the stack usage increases with system calls (which I really don't want to go through and look at their local variable usage). 

Is there a flag I have to set for the system to report stack errors?  I am presuming that I have a stack error because:

a) I reduced the stack on a number of tasks

b) The application runs erratically

c) When I look at the task summary, the information for different tasks seems to have been overriden

d) When I restore the stack sizes, the application runs as it did, there is no strangeness in the task summary

But, I don't get a halt/panic due to a stack error. 

Any ideas?

Thanx,

myke

0 Kudos
Reply
3,471 Views
c0170
Senior Contributor III

Hello Myke Predko,

I believe TAD uses the stack monitor feature in MQX which calculates the stack usage based on a pattern (maximum stack usage, how far stack has gone down for each task). If an application enables the stack monitor, the entire stack is filled with the pattern. This can be used as a watermark, therefore open your memory window and run an application for a while to execute deepest calls. Then calculate how deep the stack usage has gone.

Pattern to watch in the memory window:

#define MQX_STACK_MONITOR_VALUE (_mqx_uint)(0x7374616B)

The name of the function which fills stack with the pattern located in _mqx function:

#if MQX_MONITOR_STACK

    _task_fill_stack_internal((_mqx_uint_ptr)stack_ptr, result);

#endif

You should end up approximately with same numbers as stack usage percentages in TAD plugin. This brings up the question if my assumptions about TAD were correct, how come your application faces stack corruptions. You can prove this with watching memory window, each stack has own size and a base address. Please verify each stack space in memory window after a reduction of stack sizes if there's still the defined pattern within its own space, that would prove there's no stack overflow.

There are some static methods which could help you to find out an application's deepest call. They usually need a help from a linker to be accurate (indirect calls), like in KEIL there's callgraph and IAR has own plugin stack.

Regards,

c0170

3,470 Views
dave408
Senior Contributor II

Hi c0170​, I came across this post and thought it would be a useful way to debug a problem where I think I am running out of task stack space.  I added MQX_MONITOR_STACK to my preprocessor settings, and initially everything seemed okay with my device, which is based on the MK22FN256VLL12.  However, one of the PWM devices on the board was not working, and after much trial-and-error to determine the cause, I found that with MQX_MONITOR_STACK defined, KSDK 1.2's FTM_DRV_PwmStart() no longer worked.

If I set 100% PWM, the output would be remain low.  If I remove MQX_MONITOR_STACK, rebuild, and re-run, the PWM output operates as expected.  Have you heard of this happening before?

I have read that all this does is write the "stak" watermark in the remaining stack space.  I am not an expert with the RTOS internals nor with assembly, so I can accept with blind faith that what I'm seeing in dispatch.S supports this:

#if MQX_MONITOR_STACK

ASM_LABEL(_fill_stack)

                lsrs  r1, r1, #2

                adds  r1, r1, #1    /* Calculate size in _mqx_uints. */

                ldr r2, =0x7374616B /* Load pattern "kats". */

                b.n _fill_stack_1

ASM_LABEL(_fill_stack_0)

                str.w r2, [r0], #4  /* Store pattern to address and increment pointer to next address. */

ASM_LABEL(_fill_stack_1)

                subs r1, r1, #1      /* Decrement size counter. */

                bne.n _fill_stack_0

#endif /* MQX_MONITOR_STACK */

I've also read that MQX_KERNEL_LOGGING has to be added to enable the _klog* functions, but I have verified that kernel logging is NOT enabled, so I'm having trouble seeing how filling the stack would cause the KSDK PWM function to stop working.  Can you please help me to understand how these two things are related?

0 Kudos
Reply
3,470 Views
myke_predko
Senior Contributor III

Hi Martin,

If I understand your suggestions, you are saying:

1.  Fill each stack area with a known pattern.  The one you suggest is a 32 bit value, the ASCII string "stak", in each word of the stack area. 

2.  Run the application for a while. 

3.  Identify the locations of the stacks for each task and open a memory window in CW. 

4.  Look at how much of the "stak" pattern is overrun for each task. 

5.  Correlate what I am finding with the percentages provided by TAD.

Now, when I look at the actual stack contents, it seems like they are initially already filled with the "stak" words and when I validate them, the percentages are off by a rounding error (they algorithm doesn't seem to round up/down properly or as expected). 

So, my next step is to reduce the stacks for the various tasks and see if I can replicate what I saw before AND understand where the problem lies. 

Thanx for the pointers - I'll let you know how I make out.

myke

0 Kudos
Reply
3,470 Views
myke_predko
Senior Contributor III

Hey Martin,

Thanx for the explanation - I think you gave me the background I needed to understand how to see how much stack was being used. 

I'm still going to keep stack usage below 50% and size at 512 bytes or above for safety, but even this allows me to save a few k in the application. 

Thanx Again!

myke

0 Kudos
Reply