views:

280

answers:

2

Hello,

I am developing a multithread modular application using C programming language and NPTL 2.6. For each plugin, a POSIX thread is created. The problem is each thread has its own stack area, since default stack size depends on user's choice, this may results in huge memory consumption in some cases.

To prevent unnecessary memory usage I used something similar to this to change stack size before creating each thread:

pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_attr_getstacksize(&attr, &st1);
if(pthread_attr_setstacksize (&attr, MODULE_THREAD_SIZE) != 0) perror("Stack ERR");
pthread_attr_getstacksize(&attr, &st2); 
printf("OLD:%d, NEW:%d - MIN: %d\n", st1, st2, PTHREAD_STACK_MIN);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/* "this" is static data structure that stores plugin related data */
pthread_create(&this->runner, &attr, (void *)(void *)this->run, NULL);

EDIT I: pthread_create() section added.

This did not work work as I expected, the stack size reported by pthread_attr_getstacksize() is changed but total memory usage of the application (from ps/top/pmap output) did not changed:

OLD:10485760, NEW:65536 - MIN: 16384

When I use ulimit -s MY_STACK_SIZE_LIMIT before starting application I achieve the expected result.

My questions are:

1-) Is there any portable(between UNIX variants) way to change (default)thread stack size after starting application(before creating thread of course)?

2-) Is it possible to use same stack area for every thread?

3-) Is it possible completely disable stack for threads without much pain?

+2  A: 

Answers for #2 and #3 are no and no. Each thread needs a stack (where else do your local variables and return addresses go?) and they need to be unique per-thread (otherwise threads would overwrite each other's local variables and return addresses, making everybody crash).

As for #1... the set stack size call is precisely the answer for this. I suggest you figure out an acceptable size to create your threads with, and set it.

As for why things don't look right to you in top.... top is a notorious liar about memory usage. :-) Is stuff actually failing to be allocated or getting OOM-killed? Are thread creations failing? Is performance suffering and paging to disk increasing? If the answer to these questions is no, then I don't think there's much to worry about.

Update based on some comments below and above:
First, 16KB is still pretty big for something that you say doesn't need much stack space. If you really want to go small, I would be tempted to say 4096 or 8192 on x86 Linux. Second, yes you can set your CPU's stack pointer to something else.. But when you malloc() or mmap(), that's going to take up space. I don't know how you think it's going to help to set the stack pointer to something else. That said, if you really feel strongly that the thread that calls main() has too big of a stack (I would say that is slightly crazy) and that pthread_attr_setstacksize() doesn't let you get small enough (?), then maybe you can look into non-portable stuff like creating threads by calling the clone() syscall and specifying stacks based on the main thread's stack pointer, or a buffer from elsewhere, or whatever. But you're still going to need a stack for each thread and I have a feeling top is still going to disappoint you. Maybe your expectations are a little high.

asveikau
That's exactly what he's doing, check line 2 of his source!
Puppe
Yes Puppe, that's exactly what I am doing. It doesn't wor as I expected even with acceptable stack size. As for Q3, I am sure there are third party libraries around which can disable stack even for processes. So there should be a way to simulate stack on the heap.
eyazici
@eyazici - OK, well, the stack pointer is a CPU register and you can set it to anything you want, including something you got from malloc() or mmap(). But from your question I had no idea that's what you were asking -- and hey, even if you get it from somewhere else, it's still a stack, it's still going to consume memory, etc.
asveikau
AS for top: I can use debugger and /proc/PID/stat as well, I say top/ps for clarification. The memory usage of the threads is also reflected to overall system memory usage.
eyazici
@asveikau - My plugins (so the associated threads) does not need so much stack size, a dynamically allocated stack is more suitable for me. Even I get stack from somewhere else, it's stil stack as a data structure but it has completely different mechanism.
eyazici
*top* tells the truth, but the truth it tells is not usually the one you want. In particular, it may well be reporting either total memory (including memory mapped files!) or resident memory (excluding anything paged out). The interesting factor is in fact usually the number of private memory pages allocated to the process; that's the space which is definitely not used for something else. I can't remember if that's shown by default...
Donal Fellows
+1  A: 

I have seen this problem as well. It is unclear how the stacks are accounted for but the "extra" space is counted against your total VM and if you run up against your process boundary you are in trouble (even though you aren't using the space). It seems dependent on what version of Linux you are running (even within the 2.6 family), and whether you are 32 bit or 64 bit.

mfkilian
It's 32-bit CentOS release 5.3, kernel 2.6.18
eyazici