Loading JPEG images in parallel

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Loading JPEG images in parallel

Post by porridge »

Hello,

Since I think this is more about internals than usage, I decided to post in this forum, hope it's OK.

I'm using the gographics/imagick Go language binding for imagemagick in my program, whose main function is to load, resize and save a lot of JPEG files as fast as possible (in parallel). After doing some experiments I came to the conclusion that the bottleneck is loading pictures, and what is more, it seems it is performed serially.

After taking a dive into imagemagick sources (version 6.6.9.7 as this is what Ubuntu 12.04 precise has) I've discovered that magick/constitute.c:ReadImage seems to be acquiring a mutex if the codec does not support threading:

Code: Select all

if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
  LockSemaphoreInfo(constitute_semaphore);                 
A quick grep for NoThreadSupport seems to indicate that one of the few codecs which does not support threading is coders/jpeg.c, which is the one I care about most :-(

Some questions:
- is the above assessment correct, or did I get something wrong?
- why is there no thread support for JPEG codec?
- are there plans to change this?
- do I have any other options?

regards,

Marcin
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Loading JPEG images in parallel

Post by magick »

The JPEG delegate library is not thread safe so ImageMagick must single thread the JPEG library.
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by porridge »

Thanks, this answers the first two questions. Should I understand that there are no plans to change this, nor there are any ways around it?
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Loading JPEG images in parallel

Post by magick »

The only way to change it is to make the JPEG library thread safe. We didn't write the JPEG library. If you want it thread safe, send a note to the JPEG developers. Once its thread-safe, we can remove the mutex from ImageMagick.
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by porridge »

Could you please expand a bit on what makes the jpeg library thread-unsafe? I've found two threads about thread-safety of libjpeg-turbo (which seems to be what imagemagick is linked against at least on Ubuntu). The first[1] mentions usage of setjmp/longjmp and the other[2] the fact that tjGetErrorStr() does not take a tjhandle argument.

Is one of them the issue you have in mind? Or are they perhaps one and the same thing (I haven't looked at the code).

1. http://sourceforge.net/p/libjpeg-turbo/ ... /28603968/
2. http://sourceforge.net/p/libjpeg-turbo/ ... /30335490/
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Loading JPEG images in parallel

Post by magick »

That is a question for the JPEG developers. The JPEG delegate library includes the file libjpeg.txt that says: "Note: the JPEG library currently is not thread-safe."
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by porridge »

Hm, I had a look at that file in version 8d, and it says:
[...]
This is discussed further under "I/O suspension", above. (Note: the JPEG
library currently is not thread-safe. You must not call jpeg_consume_input()
from one thread of control if a different library routine is working on the
same JPEG object in another thread.)
[...]
The parentheses suggest that lack of thread safety only applies to multiple threads working on the same JPEG object. If my interpretation is correct, then I think it would make sense to have a mutex per image handle, rather than a global one (which is currently the case, right)?
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Loading JPEG images in parallel

Post by magick »

If you can confirm with the JPEG developers that JPEG is thread safe as you suggest-- we will enable multiple threads for the JPEG coder in the next release of ImageMagick. We do have the setjmp() issue but we may be able to work around that.
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by porridge »

Here's what I got from one of the libjpeg developers:
Guido Vollbeding <guido@jpegclub.org>
The parentheses suggest that lack of thread safety only applies to multiple threads working on the same JPEG object. I'd like to clarify if it is fine to have multiple concurrent threads using libjpeg8 if they work on separate jpeg objects.
Yes, you are totally right here, I have nothing to add.
englishl1989
Posts: 2
Joined: 2014-09-17T03:35:44-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by englishl1989 »

Can you confirm if and/or what version of ImageMagick this has been added to?
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Loading JPEG images in parallel

Post by magick »

ImageMagick 6.8.9-8, available in a few weeks.
englishl1989
Posts: 2
Joined: 2014-09-17T03:35:44-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by englishl1989 »

Brilliant, thank you.
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by porridge »

Hello again,
I tried running my program against imagemagick library version 6.8.9.9-3 as distributed by Debian and unfortunately still at most one image decoding thead seems to be running at a time. I had a look at the source and I can see the ifdefs such as:

#if JPEG_LIB_VERSION < 80
entry->thread_support=NoThreadSupport;
#endif

which at first sight looked promising. However given that that value is simply zero:

./magick/magick.h: NoThreadSupport = 0x0000,

it seems to me that not setting thread_support to any value is equivalent to setting it to NoThreadSupport.

Could you let me know if what I write make sense or is just a red herring?
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Loading JPEG images in parallel

Post by magick »

Notice the call to SetMagickInfo(). It initializes the thread support, by default, to DecoderThreadSupport | EncoderThreadSupport).
porridge
Posts: 9
Joined: 2014-04-25T13:52:28-07:00
Authentication code: 6789

Re: Loading JPEG images in parallel

Post by porridge »

Thank you for the fast response, I'll keep digging.
Post Reply