nickds1

Easy way to monitor peak stack usage...

1 post in this topic

Hi,

I needed a way to see how much of my C++ stack was being consumed in my MSP application - the traditional way is to "poison" the stack with a known pattern, and then to see how much of it gets burnt away.

So I wrote the following - hope folk find it useful:

The following code allows you to simply do this and to check at any point how much of the pre-allocated stack was consumed during peak usage, i.e. how close your app got to the bottom of the stack, or indeed, whether it over-ran. The TI CCS documentation is completely wrong in the names it gives for the global symbols that define the size and start of the stack - needs to be updated,

Stick this code (or similar) wherever you want to report on/check stack usage <smallest number of byes left free on the stack since initialisation>/<configured size of the stack>.

#if defined(STACK_CHECK)
	std::printf( "Stack: %d/%d\n", stackMinFreeCount(), stackMaxSize() );
#endif
and then, in your main code you need to poison the stack as early as possible and then define the reporting routines:
// Define STACK_CHECK to include stack usage diagnostics
#define STACK_CHECK

#if defined(STACK_CHECK)
#define STACK_INIT  0xBEEF				// Pattern to use to initially poison the stack
extern uint16_t  _stack;                // Start of stack (low address)

uint16_t stackMinFreeCount(void);
uint16_t stackMaxSize(void);
#endif

#if defined(__cplusplus)
extern "C"
{
#endif
#if defined(__TI_COMPILER_VERSION__) || \
	defined(__GNUC__)
int _system_pre_init( void )
#elif defined(__IAR_SYSTEMS_ICC__)
int __low_level_init( void )
#endif
{
	//... stuff...

#if defined(STACK_CHECK)
	//
	// Poison the stack, word by word, with a defined pattern
	//
	// Note that _system_pre_init is the earliest that we can
	// do this and that it may not be possible in TI-RTOS
	//
	// When we call the __get_SP_register intrinsic (same on IAR & CCS), it will return the address
	// of the RET address for the caller of this routine. Make sure that we don't trash it!!
	//
	register uint16_t *stack = &_stack; // Address of lowest address in .stack section
	register uint16_t *stack_top = reinterpret_cast<uint16_t *>(__get_SP_register());

	do {
		*stack++ = STACK_INIT;			// Poison stack addresses
	} while (stack < stack_top);		// Stop before top of stack to leave RET address
#endif

	return 1;
}
#if defined(__cplusplus)
}
#endif

#if defined(STACK_CHECK)
/**
 * Check how deep the stack usage has been
 *
 * \return	\c uint16_t		Minimum number of bytes to bottom of stack
 */

extern uint16_t	__STACK_END;		// End of data
extern uint16_t	__STACK_SIZE;		// Linker-set size of stack 

uint16_t stackMinFreeCount(void)
{
	const uint16_t *stack = &_stack;
	uint16_t freeCount = 0;

	while (*stack == STACK_INIT && stack++ <= &__STACK_END)
	{
		freeCount++;
	}
	return freeCount << 1;
}

/**
 * Return size of C++ stack
 *
 * Set by the linker --stack_size option
 *
 * \return	\c uint16_t		Configued maximum size of the stack in bytes
 */
uint16_t stackMaxSize(void)
{
	return static_cast<uint16_t>( _symval(&__STACK_SIZE) );
}
#endif


int main(void)
{
... stuff
#if defined(STACK_CHECK)
	std::printf( "Stack: %d/%d\n", stackMinFreeCount(), stackMaxSize() );
#endif
...stuff
}

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now