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.
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
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__);
}
Thanks, I will try this out and let you know if it was the case or not - niffy technique.
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…