Stack usage tools

Is there any tool or api for determining the stack usage or remaining? I have a potential stack overflow problem I am trying to diagnose.

I don't know of such a tool, but a while back I have proposed a "workaround" by taking a stackpointer snapshot in setup() or even a STARTUP() macro and then call a function which returns the difference between the address of one of its local variables and that base address wherever you want to know the current utilisation of the stack.

I am eternally impressed by your ideas and ability to find links and posts. I have a mesh endnode that is running in a complex pattern of sleeping and waking on RTC or interrupt that I think is using up free memory but not enough to have it restart so figure it could be stack usage because there is a big usage of local variables (arrays) doing scene analysis.

1 Like

I’m somewhat disappointed about myself as I expected that I had a sample code in that post I linked but I obviously never went back to add the code after I first posted that.

An omission I’m trying to catch up on ASAP :wink:


Update:

This would be the function (plus some test code)

// --------------------------------------------------------------------------------------------------------------
uint32_t usedStack(const char* funcName) {
  static uint32_t base = (uint32_t)&funcName;   // initialise base address on first call
  Serial.printlnf("%s: \t 0x%08lx - 0x%08lx = %lu", funcName, base, (uint32_t)&funcName, base - (uint32_t)&funcName);
  return (uint32_t)&funcName - base;
}
// --------------------------------------------------------------------------------------------------------------

void startup() {
  Serial.begin();
  delay(1000);                                  // allow for serial monitor to engage
  usedStack(__func__);
}

STARTUP(startup())

int stackInfo = -1;

void setup() {
  stackInfo = usedStack(__func__);
  Particle.variable("stackInfo", stackInfo);
}

void loop() {
  static uint32_t msLoop = 0;
  if (millis() - msLoop < 1000) return;
  msLoop = millis();
  stackInfo = usedStack(__func__);
  
  char s[128];
  s[sizeof(s)-1] = '\0';
  memset(s, '@', sizeof(s)-1);
  
  s[random(0,sizeof(s)-1)] = '\0';
  foo(s);
}

void foo(const char* str) {
  char s[strlen(str)+1];
  memset(s, 0, sizeof(s));
  strcpy(s, str);
  memset(s, 'F', random(0, strlen(s)));
  Serial.println(s);
  s[random(0,sizeof(s)-1)] = '\0';
  usedStack(__func__);
  bar(s);
}

void bar(const char* str) {
  char s[strlen(str)+1];
  memset(s, 0, sizeof(s));
  strcpy(s, str);
  memset(s, 'B', random(0, strlen(s)));
  Serial.println(s);
  usedStack(__func__);  
}
2 Likes

Thanks, I will try this out and let you know if it was the case or not - niffy technique.

1 Like

Result - it is not the stack usage or at least whilst I have been monitoring it has not shown anything abnormal. I am impressed by how little the stack is being used, activityAnalysis is the deepest level of function call. A function call appears to always put 64 bytes on the stack

loop:  0x20018b8c - 0x20018b44 = 72
checkSensor:  0x20018b8c - 0x20018afc = 144
resize_image:  0x20018b8c - 0x20018abc = 208
blobDetection:  0x20018b8c - 0x20018ac4 = 200
sceneAnalysis:  0x20018b8c - 0x20018aec = 160
activityAnalysis:  0x20018b8c - 0x20018a64 = 296

Don't pay too much attention to the absolute numbers - this should mainly help to get a feeling of what's going on.

The stack requirement for a function varies with the parameter list, the return type and the amout of local variables used (plus four bytes for the return address to jump back to the calling instruction - and possibly a set of registers).
And the optimizer may also decide to change things a bit (amongst other things it may inline a function call or keep parameters in a register).

It doesn’t look like stack overrun is really what I need to know. As they say in the Apprentice show - the search continues…

1 Like