To determine the optimal size of a thread's stack, multiply the largest number of nested subroutine calls by the size of the call frames and local variables. Add to that number an extra amount of memory to accommodate interrupts. This process is difficult to perform because stack frames vary in size, and it might not be possible to estimate the depth of library function call frames.
You can also run your program using a profiling tool that measures actual stack use. This is commonly done by poisoning the stack before use by writing a distinctive pattern, and then checking for that pattern after the thread completes. DECthreads will use this mechanism when run with metering enabled. Note that any such monitoring tools will usually increase the amount of stack use.