G'MIC stability under OSX

Hi!

I’ve managed to somehow build a minimalistic failing command.

I get a crash as soon as I have four nested -local commands:

"-verbose + -l[0] -l[0] -l[0] -l[0] -endl -endl -endl -endl"

This is still working fine:

"-verbose + -l[0] -l[0] -l[0] -endl -endl -endl"

The crash occurs just at the beginning of the inner gmic::_run() function call.

Could it be a simple problem of stack size?

Ha yes, that could be a problem with the stack size.
I had such problems on Windows, and did a lot of work already to reduce the stack usage, but maybe this was not enough for MacOSX ?.
It’s a bit strange, because the stack size is known to be particularly small by default on Windows. On MacOSX, I have no ideas. Is it possible to allow a bigger stack size ?

From Apple’s documentation:

Apparently one can change the stack size via a linker flag:

-Wl,-stack_size,1000000

should set the stack size to 16MB.

However, if I set this flag my program gets killed with an obscure

Killed: 9

message and nothing else… therefore I could no check my hypothesis yet.

I have tried with various values of the stack size, always with the same result.
I have to admit that this is driving me a bit crazy! :angry:

This has made me crazy for a couple a years now.
After all this time, I’m not crazy anymore, just a bit bored :smile:

I think this time I got it fixed!

The trick was to force the stack size of newly created threads to some large value (I’ve set it to 8MB but that’s probably too much), using pthread_attr_setstacksize().

I could finally run the freaky details filter under OSX with four threads and see the CPU usage going well above 300%! However, I had no time yet for more extensive and systematic tests…

I have created a pull request on GitHub with the modified code that runs on my system.

@KaRo: could you check if things become stable on your system as well? You can either wait until David updates the official repository, or clone my fork: GitHub - aferrero2707/gmic-minimal: G'MIC is a full-featured open-source framework for image processing, providing several different user interfaces to convert/manipulate/filter/visualize generic image datasets, ranging from 1d scalar signals to 3d+t sequences of multi-spectral volumetric images, including 2d color images.

Sounds really promising. I’ll try but not in the next few days, I am fully occupied. Let me just wait for Davids updates.

Awesome news!
Actually, yes, reading this from : Technical Q&A QA1419: Customizing Process Stack Size

Q: My application maintains a large number of concurrent threads and needs to use a large amount of stack allocated data. How can I protect against overflowing my allocated stack space?

A: My application maintains a large number of concurrent threads and needs to use a large amount of stack allocated data. How can I protect against overflowing my allocated stack space?

Each Mac OS X process is launched with a default stack size of 8 Megabytes. This allocation is used exclusively for the main thread’s stack needs. Each subsequent thread created is allocated its own default stack, the size of which differs depending on the threading API used. For example, the Mac OS X implementation of Pthreads defines a default stack size of 512 Kilobytes, while Carbon MPTasks are created with a 4 Kilobyte stack.

Then I see that 512Kb is indeed too small.
Holy crap! That was just this ? What a waste of time! I had the same issue on Windows, but at least, the error message was "Stack overflow" which was clear enough to understand what was going on…

I’ve actually already worked hard these last years to decrease the stack usage in the G’MIC code (to fix the issue on Windows). The fact that the stack size for the main thread and the secondary threads are not the same didn’t help finding the issue. That’s really awesome to know, thanks a lot Andrea!

So, now, it would be great to determine the “optimal” stack size for each thread. I think 8Mb is maybe too much. On Windows, I’ve used a #pragma to set it to approx. 6.5Mb (line 147, file gmic.h). Maybe you could try with 6.5Mb too. Trying this ultimate recursive test to determine the best size could help: While the following code crashes, you need to add some stack size.

 gmic _l=0 -m "foo : _l={\$_l+1} -foo" -parallel \"-skip\",-foo

which gives this (on Linux, so with a correct stack size and no crash) :

[gmic]-0./ Start G’MIC interpreter.
[gmic]-0./ Set global variable _l=‘0’.
[gmic]-0./ Import custom commands from expression ‘foo : _l={$_l+1} -foo’ (added 1 command, total 6197).
[gmic]-0./ Execute 2 commands ‘-skip,-foo’ in parallel and wait thread termination immediately.
[gmic]-0./*thread1/foo/ Set global variable _l=‘1’.
[gmic]-0./*thread1/foo/foo/ Set global variable _l=‘2’.
[gmic]-0./*thread1/foo/foo/foo/ Set global variable _l=‘3’. :joy:
[gmic]-0./*thread1/foo/foo/foo/foo/ Set global variable _l=‘4’.
[gmic]-0./*thread1/foo/foo/foo/foo/foo/ Set global variable _l=‘5’.
[gmic]-0./*thread1/foo/foo/foo/foo/foo/foo/ Set global variable _l=‘6’.
[gmic]-0./*thread1/foo/foo/foo/foo/foo/foo/foo/ Set global variable _l=‘7’.

[gmic]-0./*thread1/foo/foo/(…)/foo/foo/foo/foo/ Set global variable _l=‘61’.
[gmic]-0./*thread1/foo/foo/(…)/foo/foo/foo/foo/ Set global variable _l=‘62’.
[gmic]./*thread1/foo/foo/(…)/foo/foo/foo/foo/ *** Error *** Call stack overflow (infinite recursion ?).

Please, tell us. I’m so excited by the news. I think this could deserve a new stable release (currently planed is 1.6.6.0).
Having in the same week the GEGL stuff included in the plug-in for GIMP 2.9, and the bug fix for MacOSX… wow! :joy:

According to :

http://man7.org/linux/man-pages/man3/pthread_create.3.html

On Linux/x86-32, the default stack size for a new thread is 2
 megabytes.  Under the NPTL threading implementation, if the
RLIMIT_STACK soft resource limit at the time the program started has
any value other than "unlimited", then it determines the default
stack size of new threads.  Using pthread_attr_setstacksize(3), the
stack size attribute can be explicitly set in the attr argument used
to create a thread, in order to obtain a stack size other than the
default.

so it may be a good start to try 2 Mb for the default stack size no ?

Just my parallel enabled git version:

~ gmic _l=0 -m "foo : _l={\$_l+1} -foo" -parallel \"-skip\",-foo [gmic]-0./ Start G'MIC interpreter. [gmic]-0./ Set global variable _l='0'. [gmic]-0./ Import custom commands from expression 'foo : _l={_l+1} -foo’ (added 1 command, total 4473).
[gmic]-0./ Execute 2 commands ‘-skip,-foo’ in parallel and wait thread termination immediately.
[gmic]-0./*thread1/foo/ Set global variable _l=‘1’.
[gmic]-0./*thread1/foo/foo/ Set global variable _l=‘2’.
[gmic]-0./*thread1/foo/foo/foo/ Set global variable _l=‘3’.
[gmic]-0./*thread1/foo/foo/foo/foo/ Set global variable _l=‘4’.
[gmic]-0./*thread1/foo/foo/foo/foo/foo/ Set global variable _l=‘5’.
[gmic]-0./*thread1/foo/foo/foo/foo/foo/foo/ Set global variable _l=‘6’.
[gmic]-0./*thread1/foo/foo/foo/foo/foo/foo/foo/ Set global variable _l=‘7’.
[gmic]-0./*thread1/foo/foo/(…)/foo/foo/foo/foo/ Set global variable _l=‘8’.
[gmic]-0./*thread1/foo/foo/(…)/foo/foo/foo/foo/ Set global variable _l=‘9’.
[gmic]-0./*thread1/foo/foo/(…)/foo/foo/foo/foo/ Set global variable _l=‘10’.Illegal instruction: 4

Hi! Is this my patched version or the one with the default stack size of 512KB?

Its the default one, no time as i said!

Carmelo Dr Raw noreply@discuss.pixls.us schrieb am Fr., 11. Sep. 2015
09:27:

Hi David!

I’m afraid I’ll not have the possibility to do more work before next tuesday… I’ll be travelling all day today, and then I have a busy weekend with the kids :wink:

In any case, as soon as I have managed to test your suggestion, I’ll drop a message here.

OK, no problem.
You already made my day :smile:
Maybe I’ll just set the stack size to 2Mb by default on Linux (on the current git), so that people working on Linux don’t get oversized stack size when using G’MIC.
Determining the optimal stack size shouldn’t be a big issue I think.

Ok just some quick tests on Linux.
2Mb → Crash (goes to iteration 40).
3Mb → Crash (goes to iteration 61).
4Mb → OK

I’ll try some other advanced processing with 4Mb, to see if this is a robust limit for a stack size.

OK, so 4Mb seems to be working fine on Linux.
I’ve also added the set_stacksize() call in the G’MIC plug-in code. I’m waiting for your feedback about these changes on MacOSX.

1 Like

Really, my git version did not crash anymore!
Many thanks!!
Now I can build a git prerelease with parallels enabled and optimized!
Karsten

1 Like

You are welcome! :slight_smile: