Using G'MIC with limited resources


#1

I am cognizant of the limitations of my system (an aging low-powered win10 laptop). I tend to keep my PlayRaw and exercise workflow lean, making sure that I break commands and operations down into manageable chunks, especially when the input image is large. To do that, I usually save intermediary files and make sure that I don’t add too many images in the buffer.

(I am still learning how to use fill to do things, e.g., without using buffer space, and doing more complex calculations in one go. I know we have addressed that before but I still don’t get it. I might write more about that later in this thread.)

Which brings me to the question: is there a way to be kinder to my machine? I know G’MIC has options for Multi-threaded and in-place evaluation, etc., but I would like concrete examples. I also know that ImageMagick, e.g., has memory and processing management parameters and settings, not all of which could be configured post-build. I bet G’MIC (and CIMG) has some neat tricks too. Please share your ideas. :slight_smile:

What happens when G’MIC is doing too much on my laptop:
1. Stops operation and says that there is not enough memory. The best outcome.
2. Makes everything else on my system stutter, stall or crash. Usually, it is the first but the second makes my rad :sunglasses: tunes :musical_note: stutter and stall; and the latter has happened at least to a Java app. Don’t ask me why I would use that. :stuck_out_tongue: I understand that many apps think they need to suck up all of the resources; I am looking at you Firefox! So, it is not necessarily G’MIC’s fault.
3. Today, I encountered an error:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

when I mistakenly used search_dichotomic on two (tiny) images instead of one, without a repeat $! l[$>]endl done. I guess the buffer overloaded due to having too many images being added to the process but not enough being removed. Makes sense that there would be an error; however, it would be nice if there were a message to indicate what happened.

Speaking of error messages, it isn’t a big deal but the error messages for native and non-native files are different when they don’t exist. Maybe I am just slow or tired but it usually takes me several seconds to parse *** Error *** gmic::fopen(): Failed to open file 'a.gmz' with mode 'rb'. even though I know what it means, whereas Unknown command or filename… is much easier read.

>gmic a.gmz
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input file 'a.gmz' at position 0
[gmic]-0./ *** Error *** gmic::fopen(): Failed to open file 'a.gmz' with mode 'rb'.

>gmic a.png
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input file 'a.png' at position 0
[gmic]-0./ *** Error *** Unknown command or filename 'a.png' (did you mean 'and' ?).

(G'MIC staff) #2

A few things to know about multi-threaded/in-place evaluation of math formulas:

  • Multi-threading in G’MIC relies on the OpenMP library. So, there are ways to set OpenMP environment variables to change the default OpenMP behavior, for any program that uses it. In particular, setting the environment variable OMP_NUM_THREADS will tell OpenMP to limit the number of threads used (see: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.3/com.ibm.xlc1313.aix.doc/compiler_ref/ruomprun4.html). Basically, set it to 1 to disable multi-threading.

  • Another solution consists in starting your expression with one of the special character >, <, * or : . The characters > and < tell G’MIC the math expression must be evaluated in-place in forward or backward order, so it also disable multi-threading. If you don’t specify these starting characters, G’MIC tries to guess what the best mode could be for evaluating the math expression. It tries to use multi-threading and avoid buffer copies when possible, but sometimes the math expression is a bit tricky to analyze and G’MIC won’t be able to determine the optimal mode (leading in no multi-threading, or unnecessary buffer copies). It’s always good to specify those characters for complex expressions.

Looks like a bug to me, I’m interested by having a command line to reproduce the bug easily :slight_smile:

This will be fixed for the next release, I’ve written some code this morning to fix this (https://framagit.org/dtschump/gmic/commit/c3c21523be8f3085fae3fa8132521bf1c6352ef1).


#3

Sorry, I don’t remember the CLI command and have altered the filters since. It has something to do with search_dichotomic on a source image and a copy, each processed differently then cropped at the same spot (a very tiny crop of the “town” in [PlayRaw] Landsat 8 image of Lake Elton). As mentioned, I forgot to apply it on the images separately using the repeat local loop. Lastly, I had a sequence of 3 search_dichotomics. This time I only got the expected error:

*** [instance(0,0,0,0,0000000000000000,non-shared)] gmic<float>::CImg(): Failed to allocate memory (513.8 Kio) for image (160,274,1,3).

#4

Could you elaborate on this? I mean break > , < , * and : down a bit more because I am unfamiliar with, or at least not used to talking about, in-place processing, multi-threading and buffer copies.


(G'MIC staff) #5

From the reference documentation:

- Multi-threaded and in-place evaluation: 
 
       . If your image data are large enough and you have several CPUs available, it is likely that 
          the math expression passed to a 'fill' or 'input' command is evaluated in parallel, 
          using multiple computation threads. 
       . Starting an expression with ':' or '*' forces the evaluations required for an image to be 
          run in parallel, even if the amount of data to process is small (beware, it may be slower 
          to evaluate in this case!). Specify ':' (instead of '*') to avoid possible image copy 
          done before evaluating the expression (this saves memory, but do this only if you are 
          sure this step is not required!) 
       . If the specified expression starts with '>' or '<', the pixel access operators 
          'i(), i[], j()' and 'j[]' return values of the image being currently modified, 
          in forward ('>') or backward ('<') order. The multi-threading evaluation of the 
          expression is also disabled in this case. 
       . Function 'critical(operands)' forces the execution of the given operands in a single thread at a 
          time. 

#6

I have read the documentation. I am unsure of what it is saying, and how to use > , < , *, : and critical(operands) (e.g., why would direction matter?). I just don’t know what is suitable for me. My laptop has a i3-2310M (2 cores, 4 threads) and 4GB memory, often with other apps running.


#7

Try these:

gmic 3 f. "j(-1)+1" # output (1,1,1)
gmic 3 f. ">j(-1)+1" # output (1,2,3)

The first is the usual way, where the j(-1) reference looks at the source pixel to the left and adds 1 to its value. The second looks at the pixel to the left in the output buffer, which means it changes as it goes. Maybe that helps!


#8

In other words, > and < changes the math. I guess that leaves :, * and critical(operands). I suppose I could eliminate * as well since I would like to save memory…


#9

Well I guess it’s more like the loop direction. Using “>” In a 1D image the loop begins from the leftmost pixel, you can guess what happens the other way :slight_smile:


#10

Okay, that makes more sense. :slight_smile: