0

Am trying to guess-timate how much stack to allocate on per thread basis. Found hints that suggest program should scribble a known pattern (ex: 0xEF) in memory, to get upper/lower bounds of stack.

Can someone provide quick C program to do so? Is this truly the way to go? Any other suggestions?

Thank you for assisting with this doubt.

cpx
  • 17,009
  • 20
  • 87
  • 142
frododot
  • 127
  • 2
  • 16

2 Answers2

1

If you have complete control of your program( code ), it's a nonsense trying to find the size because you would be the one who's telling the OS to allocate the specific amount of stack size when you're creating a thread using CreateThread or pthread_create. However, if you don't, depending on your OS, you can either call pthread_attr_getstack (on unix) or VirtualQuery(on Windows), allocate a stack-based variable, and calculate the distance between the base address of the stack and the position of your variable.

JosephH
  • 8,465
  • 4
  • 34
  • 62
0

An alternative way to get an estimate of the stack usage is to read the stack pointer value in every function and update the minimum and maximum stack pointer variables. At the end of the program the difference between the two values will give you the estimate.

In order to read the value of the stack pointer you can:

  • Implement an assembly function (doing mov r/eax, r/esp + ret for the x86 CPU)
  • Do the same (w/o ret, of course) using inline assembly if supported by your compiler
  • Implement something like the below (which may not work always/everywhere due to code optimization)

Code:

#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

// uintptr_t is an unsigned integer type from stdint.h
// that is capable of holding a pointer.
// If you don't have it in your compiler, use an
// equivalent, which may be size_t (stddef.h) or
// UINT_PTR (windows.h) or something else.
uintptr_t StackPointerMin = (uintptr_t)-1;
uintptr_t StackPointerMax = 0;

void UpdateStackUsageInner(int dummy, ...)
{
  va_list ap;
  volatile char* p;
  uintptr_t StackPointer;

  va_start(ap, dummy);
  p = va_arg(ap, volatile char*);
  StackPointer = (uintptr_t)p;

  if (StackPointer < StackPointerMin) StackPointerMin = StackPointer;
  if (StackPointer > StackPointerMax) StackPointerMax = StackPointer;

  va_end(ap);
}

void UpdateStackUsage()
{
  volatile char c = 'a';
  UpdateStackUsageInner(0, &c);
}

void DoSomething(void)
{
  char c[1024+1];
  UpdateStackUsage();
  memset(c, '*', sizeof(c));
  c[sizeof(c)-1] = '\0';
  printf("%s\n", c);
}

int main(void)
{
  UpdateStackUsage();
  DoSomething();
  printf("Approximate stack usage: %lu\n",
         (unsigned long)(StackPointerMax - StackPointerMin));
  return 0;
}

Output:

********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
********************************************************************************
****************************************************************
Approximate stack usage: 1040

I also know that some compilers support hooking function entry (and probably exit), which can simplify the task because with that you won't need to insert UpdateStackUsage(); into all/many of your functions. That's been discussed here.

Community
  • 1
  • 1
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180