How to determine maximum stack usage in embedded system?
Asked Answered
F

2

10

When I give the Keil compiler the "--callgraph" option, it statically calculates the exact "Maximum Stack Usage" for me.

Alas, today it is giving me a "Maximum Stack Usage = 284 bytes + Unknown(Functions without stacksize...)" message, along with a list of "Functions with no stack information".

Nigel Jones says that recursion is a really bad idea in embedded systems ("Computing your stack size" 2009), so I've been careful not to make any mutually recursive functions in this code.

Also, I make sure that none of my interrupt handlers ever re-enable interrupts until their final return-from-interrupt instruction, so I don't need to worry about re-entrant interrupt handlers.

Without recursion or re-entrant interrupt handlers, it should able to statically determine the maximum stack usage. (And so most of the answers to How to determine maximum stack usage? do not apply). My understanding is that the software that handles the "--callgraph" option first finds the maximum stack depth for each interrupt handler when it's not interrupted by a higher-priority interrupt, and the maximum stack depth of the main() function when it is not interrupted. Then it adds them all up to find the total (worst-case) maximum stack depth. That occurs when the main() background task is at its maximum depth when it is interrupted by the lowest-priority interrupt, and that interrupt is at its maximum depth when it is interrupted by the next-lowest-priority interrupt, and so on.

I suspect the software that handles --callgraph is getting confused about the small assembly-language functions in the "Functions with no stack information" list. The --callgraph documentation seems to imply that I need to manually calculate (or make a conservative estimate) how much stack they use -- they're very short, so that should be simple -- and then "Use frame directives in assembly language code to describe how your code uses the stack." One of them is the initial startup code that resets the stack to zero before jumping to main() -- so, in effect, this consumes zero stack. Another one is the "Fault" interrupt handler that locks up in an infinite loop until I cycle the power -- it's safe to assume this consumes zero stack.

I'm using the Keil uVision V4.20.03.0 to compile code for the LM3S1968 ARM Cortex-M3.

So how do I use "frame directives" to tell the software that handles "--callgraph" how much stack these functions use? Or is there some better approach to determine maximum stack usage?

(See How to determine maximum stack usage in embedded system with gcc? for almost the same question targeted to the gcc compiler.)

Foehn answered 16/6, 2011 at 17:1 Comment(7)
Perhaps you can code dummy C equivalents (from the point of view of stack usage) of your assembly modules, and run your analysis with those.Adamo
I added the 'keil' tag since this is a compiler-specific question. Hopefully that will attract some more specialized eyes to the problem.Squalene
I'm not sure if you're asking for how to get GCC to do similar analysis or how to get rid of the "+ Unknown" message from Keil (or maybe you're looking for both, in which case there should be two separate questions). Since it appears you've determined that the "+ Unknown" comes from functions that use zero stack, it seems like you can essentially ignore it.Bombardon
By the way, it looks like GCC 4.6 adds the -fstack-usage option which gives the stack usage statistics on a function-by-function basis. If you combine this information with a call graph produced by the cflow or similar tool you can get the kind of stack depth analysis you're looking for (a script could probably be written pretty easily to do this). So, it looks like this can be done with GCC, but you might have to cobble together the right set of tools.Bombardon
@Michael Burr: I was hoping (wishful thinking) that there was some de-facto-standard "portable" way for me to tell the compiler a worst-case estimate of how much stack space a function uses -- similar to the way "__interrupt" is the de-facto-standard "portable" way for me to tell the compiler that some function is an interrupt handler -- that works with both gcc and other compilers.Foehn
@bta: Thank you. I now think you and Michael Burr are right -- I'm looking for both, so this needs to be two separate questions. So I went ahead and split it into two separate questions.Foehn
Have you tried the FRAME PUSH 0 or FRAME ADDRESS sp directives to tell the Keil tools that those assembly functions don't use any stack? I don't have access to the toolchain, so I'm asking just based on what the online docs say.Bombardon
B
3

Use the --info=stack in the linker option. The map file will then include a stack usage for all functions with external linkage.

In a single tasking environment, the stack usage for main() will give you the total requirement. If you are using an RTOS such as RTX where each task has its own stack, then you need to look at the stack usage for all task entry points, and then add some more (64 bytes in the case of RTX) for the task context storage.

This and other techniques applicable to Keil and more generally are described here

Blamed answered 17/6, 2011 at 20:43 Comment(0)
H
3

John Regehr of the University of Utah has a good discussion of measuring stack usage in embedded systems at http://www.embedded.com/design/prototyping-and-development/4025013/Say-no-to-stack-overflow, though note that the link to ftp.embedded.com is stale, and one occurrence of “without interrupts disabled” should have either the first or last word negated. In the commercial world, Coverity has a configurable stack overflow checker, and some versions of CodeWarrior have a semi-documented warn_stack_usage pragma. (It’s not mentioned in my version of the compiler documentation, but is in MetroWerks’ “Targeting Palm OS” document.)

Handshaker answered 18/6, 2011 at 16:33 Comment(1)
Great link, and I hope to use some of those techniques for some Freescale HCS08 work I'm doing (2KB RAM, so every byte counts and you don't want to waste 'em on unused stack). Small world: back in the 90's you created the Kagi Register app for Newton, and I created the order.kagi.com website.Coarsegrained

© 2022 - 2024 — McMap. All rights reserved.