Tool/software: TI C/C++ Compiler
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
}