Skip to main content

quad-core processor limited utilization. performance issue

18 replies [Last post]
klink
Offline
Joined: 2008-04-17
Points: 0

Hi,

I'm using JAI for the WikiSky project. The code is running on quad core systems. I noticed that JAI functions utilize only two cores at a time. In other words, no matter how many threads are running, the quad-core CPU utilization is balancing at 50%.
Is there any settings in JAI to use all available cores in parallel?

JAI operations I'm using are:
- jpeg compression/decompression
- scaling down images
- table warping for non-linear projection transformations
- cutting tiles
and so on

I'm manipulating with terrabytes of images and I really need to utilize all available resources.

Thanks,
Sergei

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
bpb
Offline
Joined: 2004-06-23
Points: 0

I meant exactly what you inferred below. When a JAI operation is created a node is merely added to a graph. The node is not "rendered", i.e., any pixels calculated until some method such as getWidth() is invoked. So if one creates a chain or graph of nodes and then renders the sink node of the chain then the time observed will be that to calculate all the nodes in the chain up to that point, at least to the extent required to satisfy the call. In the case of getWidth() only this will not cause any pixels to be calculated per se at least not that I can think of in the nominal case.

Brian

> I'm not entirely sure what you mean by "artifact of
> deferred execution."
>
> In my load testing, about 27% of the time is spent in
>
>
> com.sun.media.jai.codec.ImageEncoder.encode
>
> and about 16% is taken in
>
> javax.media.jai.PlanarImage.getWidth
>
>
> If you're saying that there is some prep-work on
> PlanarImage that doesn't get executed until the first
> call into the instance and that happens to be
> getWidth, I'd believe that, but that's still a huge
> amount of time spent in there. Especially
> considering the fact that we can't push our CPU past
> about 30% no matter how many machines/threads we
> throw at it.

klink
Offline
Joined: 2008-04-17
Points: 0

I tried to use setParallelism() with different values from 0 to 4. I didn't notice any difference.
Most of the threads sitting at lock somewhere at Jpeg encoding/decoding codec. Here's what I see when running 7 threads:

Running threads
http-80-1 [BLOCKED; waiting to lock java.lang.Object@8aca5e]
com.sun.media.jai.codecimpl.JPEGImage.(JPEGImageDecoder.java:106)
com.sun.media.jai.codecimpl.JPEGImageDecoder.decodeAsRenderedImage(JPEGImageDecoder.java:46)
com.sun.media.jai.opimage.CodecRIFUtil.create(CodecRIFUtil.java:88)
com.sun.media.jai.opimage.JPEGRIF.create(JPEGRIF.java:43)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.StreamRIF.create(StreamRIF.java:102)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.FileLoadRIF.create(FileLoadRIF.java:144)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)

http-80-2 [BLOCKED; waiting to lock java.lang.Object@8aca5e]
com.sun.media.jai.codecimpl.JPEGImage.(JPEGImageDecoder.java:106)
com.sun.media.jai.codecimpl.JPEGImageDecoder.decodeAsRenderedImage(JPEGImageDecoder.java:46)
com.sun.media.jai.opimage.CodecRIFUtil.create(CodecRIFUtil.java:88)
com.sun.media.jai.opimage.JPEGRIF.create(JPEGRIF.java:43)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.StreamRIF.create(StreamRIF.java:102)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.FileLoadRIF.create(FileLoadRIF.java:144)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)

http-80-3 [RUNNABLE]
sun.awt.image.ByteInterleavedRaster.setPixels(unknown source)
java.awt.image.WritableRaster.setRect(unknown source)
sun.awt.image.SunWritableRaster.setRect(unknown source)
sun.awt.image.ByteInterleavedRaster.setRect(unknown source)
java.awt.image.WritableRaster.setRect(unknown source)
sun.awt.image.SunWritableRaster.setRect(unknown source)
com.sun.media.jai.codecimpl.JPEGImage.(JPEGImageDecoder.java:148)
com.sun.media.jai.codecimpl.JPEGImageDecoder.decodeAsRenderedImage(JPEGImageDecoder.java:46)
com.sun.media.jai.opimage.CodecRIFUtil.create(CodecRIFUtil.java:88)
com.sun.media.jai.opimage.JPEGRIF.create(JPEGRIF.java:43)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.StreamRIF.create(StreamRIF.java:102)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.FileLoadRIF.create(FileLoadRIF.java:144)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getRendering(RenderedOp.java:888)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:799)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getSampleModel(RenderedOp.java:2233)
com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:133)

http-80-4 [BLOCKED; waiting to lock java.lang.Object@8aca5e]
com.sun.media.jai.codecimpl.JPEGImage.(JPEGImageDecoder.java:106)
com.sun.media.jai.codecimpl.JPEGImageDecoder.decodeAsRenderedImage(JPEGImageDecoder.java:46)
com.sun.media.jai.opimage.CodecRIFUtil.create(CodecRIFUtil.java:88)
com.sun.media.jai.opimage.JPEGRIF.create(JPEGRIF.java:43)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.StreamRIF.create(StreamRIF.java:102)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.FileLoadRIF.create(FileLoadRIF.java:144)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getRendering(RenderedOp.java:888)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:799)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getSampleModel(RenderedOp.java:2233)
com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:133)

http-80-5 [RUNNABLE]
sun.awt.image.codec.JPEGImageEncoderImpl.writeJPEGStream(native method)
sun.awt.image.codec.JPEGImageEncoderImpl.encode(unknown source)
sun.awt.image.codec.JPEGImageEncoderImpl.encode(unknown source)
com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:277)

http-80-6 [BLOCKED; waiting to lock java.lang.Object@8aca5e]
com.sun.media.jai.codecimpl.JPEGImage.(JPEGImageDecoder.java:106)
com.sun.media.jai.codecimpl.JPEGImageDecoder.decodeAsRenderedImage(JPEGImageDecoder.java:46)
com.sun.media.jai.opimage.CodecRIFUtil.create(CodecRIFUtil.java:88)
com.sun.media.jai.opimage.JPEGRIF.create(JPEGRIF.java:43)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.StreamRIF.create(StreamRIF.java:102)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.FileLoadRIF.create(FileLoadRIF.java:144)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getRendering(RenderedOp.java:888)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:799)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getSampleModel(RenderedOp.java:2233)
com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:133)

http-80-7 [RUNNABLE]
sun.awt.image.codec.JPEGImageDecoderImpl.readJPEGStream(native method)
sun.awt.image.codec.JPEGImageDecoderImpl.decodeAsBufferedImage(unknown source)
com.sun.media.jai.codecimpl.JPEGImage.(JPEGImageDecoder.java:110)
com.sun.media.jai.codecimpl.JPEGImageDecoder.decodeAsRenderedImage(JPEGImageDecoder.java:46)
com.sun.media.jai.opimage.CodecRIFUtil.create(CodecRIFUtil.java:88)
com.sun.media.jai.opimage.JPEGRIF.create(JPEGRIF.java:43)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.StreamRIF.create(StreamRIF.java:102)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
com.sun.media.jai.opimage.FileLoadRIF.create(FileLoadRIF.java:144)
sun.reflect.GeneratedMethodAccessor33.invoke(unknown source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(unknown source)
java.lang.reflect.Method.invoke(unknown source)
javax.media.jai.FactoryCache.invoke(FactoryCache.java:122)
javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674)
javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473)
javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getRendering(RenderedOp.java:888)
javax.media.jai.RenderedOp.createInstance(RenderedOp.java:799)
javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867)
javax.media.jai.RenderedOp.getSampleModel(RenderedOp.java:2233)
com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:133)

Bob Deen

On Apr 18, 2008, at 10:01 PM, jai-interest@javadesktop.org wrote:
> I tried to use setParallelism() with different values from 0 to 4.
> I didn't notice any difference.
> Most of the threads sitting at lock somewhere at Jpeg encoding/
> decoding codec. Here's what I see when running 7 threads:

How are you asking for data to be computed?

Also, it looks like they're all blocked trying to read the JPEG
image. It's quite possible (likely, in fact) that the file I/O
readers in general do not support multithreading. Hopefully they
will if reading different images (!).

I don't know what your operator chain looks like but you might try
putting a format operator after the read to re-tile the image and
decouple everything else from the reader. If that format has
sufficient cache space, all subsequent operations should come from
memory and not touch the file again.

-Bob

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

wikisky
Offline
Joined: 2007-11-27
Points: 0

I looked at JpegImageDecoder.java
What I found is that the class JpegImageDecoder.JPEGImage has static lock object (LOCK) that prevents simultaneous jpeg decoding operations, no matter if it's same file of different files:

class JPEGImage extends SimpleRenderedImage {

/**
* Mutex for the entire class to circumvent thread unsafety of
* com.sun.image.codec.jpeg.JPEGImageDecoder implementation.
*/
private static final Object LOCK = new Object();

private Raster theTile = null;

/**
* Construct a JPEGmage.
*
* @param stream The JPEG InputStream.
* @param param The decoding parameters.
*/
public JPEGImage(InputStream stream, ImageDecodeParam param) {
// If the supplied InputStream supports mark/reset wrap it so
// it does not.
if(stream.markSupported()) {
stream = new NoMarkStream(stream);
}

// Lock the entire class to work around lack of thread safety
// in com.sun.image.codec.jpeg.JPEGImageDecoder implementation.
BufferedImage image = null;
synchronized(LOCK) {
com.sun.image.codec.jpeg.JPEGImageDecoder decoder =
com.sun.image.codec.jpeg.JPEGCodec.createJPEGDecoder(stream);
try {
// decodeAsBufferedImage performs default color conversions
image = decoder.decodeAsBufferedImage();
} catch (ImageFormatException e) {
String message = JaiI18N.getString("JPEGImageDecoder1");
sendExceptionToListener(message, (Exception)e);
// throw new RuntimeException(JaiI18N.getString("JPEGImageDecoder1"));
} catch (IOException e) {
String message = JaiI18N.getString("JPEGImageDecoder1");
sendExceptionToListener(message, (Exception)e);
// throw new RuntimeException(JaiI18N.getString("JPEGImageDecoder2"));
}
}

Looks like there's no way around in this codec.
The question is is there other jpeg codecs that are thread safe and can be used in JAI?

Bob Deen

Ohhhh... that's nasty!!!

There are several other jpeg implementations floating about that you
might look into. It looks like you're using the older JAI codec
mechanism. There are at least two more jpeg's for the newer Image I/
O mechanism (imageread instead of fileload operator). I have no idea
if they do the same (really quite horrid) locking things but it's
worth looking into. You have to download the imageio tools package
(same place as JAI) though.

-Bob

On Apr 19, 2008, at 7:31 PM, jai-interest@javadesktop.org wrote:
> I looked at JpegImageDecoder.java
> What I found is that the class JpegImageDecoder.JPEGImage has
> static lock object (LOCK) that prevents simultaneous jpeg decoding
> operations, no matter if it's same file of different files:
>
> class JPEGImage extends SimpleRenderedImage {
>
> /**
> * Mutex for the entire class to circumvent thread unsafety of
> * com.sun.image.codec.jpeg.JPEGImageDecoder implementation.
> */
> private static final Object LOCK = new Object();
>
> private Raster theTile = null;
>
> /**
> * Construct a JPEGmage.
> *
> * @param stream The JPEG InputStream.
> * @param param The decoding parameters.
> */
> public JPEGImage(InputStream stream, ImageDecodeParam param) {
> // If the supplied InputStream supports mark/reset wrap it so
> // it does not.
> if(stream.markSupported()) {
> stream = new NoMarkStream(stream);
> }
>
> // Lock the entire class to work around lack of thread safety
> // in com.sun.image.codec.jpeg.JPEGImageDecoder
> implementation.
> BufferedImage image = null;
> synchronized(LOCK) {
> com.sun.image.codec.jpeg.JPEGImageDecoder decoder =
> com.sun.image.codec.jpeg.JPEGCodec.createJPEGDecoder
> (stream);
> try {
> // decodeAsBufferedImage performs default color
> conversions
> image = decoder.decodeAsBufferedImage();
> } catch (ImageFormatException e) {
> String message = JaiI18N.getString
> ("JPEGImageDecoder1");
> sendExceptionToListener(message, (Exception)e);
> // throw new RuntimeException(JaiI18N.getString
> ("JPEGImageDecoder1"));
> } catch (IOException e) {
> String message = JaiI18N.getString
> ("JPEGImageDecoder1");
> sendExceptionToListener(message, (Exception)e);
> // throw new RuntimeException(JaiI18N.getString
> ("JPEGImageDecoder2"));
> }
> }
>
>
> Looks like there's no way around in this codec.
> The question is is there other jpeg codecs that are thread safe and
> can be used in JAI?
> [Message sent by forum member 'wikisky' (wikisky)]
>
> http://forums.java.net/jive/thread.jspa?messageID=270237
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail: interest-help@jai.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

wikisky
Offline
Joined: 2007-11-27
Points: 0

I didn't know that imageread is newer than fileload. I'll try it out.Hope it'll better handle multithreading.

Thanks,
Sergei

Simone Giannecchini

Ciao,
I can report what is the result of my investigations on this matter.
Unfortunately ImageReader implementations are not required to be
thread safe. This affect the JAI ImageIO ImageRead operation since
multiple tiles "could" be loaded in mutlithreading
but in reality there is a nick synchornization that does serialize all
the access to the underlying ImageReader used to load single tiles
(well, moreover I am not sure that any of the availabole
implementations of JPEG ImageReaders does tiling). For the Imageio-ext
project (https://imageio-ext.dev.java.net/) we have tried to implement
a partial multithreaded ImageRead which we called ImageReadMT which
assumes that multiple reads performed on the same ImageReader are safe
(this does nto mean in general that the ImageReader has to be thread
safe, which is a morestrict requiremrnt).

What one could do could be reusing the ImageReadMT operation and
create a specific ImageReader decorator that makes use of a pool of
thread-unsafe image reader and pass this to the ImageReadMT to do
actual multithreading. Of course this is just an idea and it also has
quite some limitations, but it would be quite easy to implement and in
some conditions it could provide a huge performance gain.

Simone.

On Mon, Apr 21, 2008 at 7:45 AM, wrote:
> I didn't know that imageread is newer than fileload. I'll try it out.Hope it'll better handle multithreading.
>
> Thanks,
> Sergei
> [Message sent by forum member 'wikisky' (wikisky)]
>
> http://forums.java.net/jive/thread.jspa?messageID=270299
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail: interest-help@jai.dev.java.net
>
>

--
-------------------------------------------------------
Eng. Simone Giannecchini
President /CEO GeoSolutions S.A.S.
Via Carignoni 51
55041 Camaiore (LU)
Italy

phone: +39 0584983027
fax: +39 0584983027
mob: +39 333 8128928

http://www.geo-solutions.it

-------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

atomly
Offline
Joined: 2008-05-14
Points: 0

Are there any updates on this? We're running into a very similar problem- users upload photos to our site and we scale them down, but we're running into a lot of contention in the scaling cluster during load testing. We can only push our CPU (we're using Sun Fire T1000s) usage to about 30% and it looks like it's all because of blocking in JAI.

I guess I can try out the imageio-ext change described above and see if that helps at all, but any help would be great.

Brian Burkhalter

From the code comments the locking is apparently due to the wrapped
class over which JAI had no control:

/**
* Mutex for the entire class to circumvent thread unsafety of
* com.sun.image.codec.jpeg.JPEGImageDecoder implementation.
*/
private static final Object LOCK = new Object();

Reference: https://jai-core.dev.java.net/source/browse/jai-core/src/share/classes/c...

This means that JPEGs may be read only one at a time within the VM in
which the class is instantiated. This is not the same as the Image I/O
Framework's stated non-goal of thread safety which is worked around by
the imageio-ext project. In that case what I think is dealt with - I
have not looked into that project's details - is lack of thread safety
when using the *same* ImageReader "simultaneously" on different
threads, e.g., to read different tiles of the same image.

Note that the "ImageRead" JAI operation included in JAI Image I/O
Tools is AFAIK thread-safe: the computeTile() method synchronizes on
the ImageReader being used. If you are using the JAI "FileLoad"
operation a simple change would be to use "ImageRead" instead. I think
this would work just by changing that one string and of course
installing JAI Image I/O Tools.

Presumably all the uploaded source images are JPEGs? What are the
typical dimensions?

There are a number of factors which could be at play here:

* the JPEG reader lock you mention;
* re-reading the same JPEG due to a cache flush;
* if tiling is used, contention for the same tile in different
scheduler threads.

This last problem is due to scaling (or other area or geometric
operations which require context) needing a "corona" around the
backward mapped destination region in order to compute the latter.
Fixing it would be non-trivial.

On May 14, 2008, at 10:34 AM, jai-interest@javadesktop.org wrote:

> Are there any updates on this? We're running into a very similar
> problem- users upload photos to our site and we scale them down, but
> we're running into a lot of contention in the scaling cluster during
> load testing. We can only push our CPU (we're using Sun Fire
> T1000s) usage to about 30% and it looks like it's all because of
> blocking in JAI.
>
> I guess I can try out the imageio-ext change described above and see
> if that helps at all, but any help would be great.
> [Message sent by forum member 'atomly' (atomly)]
>
> http://forums.java.net/jive/thread.jspa?messageID=274348

>^..^< >^..^<

Brian Burkhalter
Java Imaging and Video
Sun Microsystems, Inc.

This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

atomly
Offline
Joined: 2008-05-14
Points: 0

Thanks for your help. I'll try out your suggestions.

Also, in my profiling, I'm finding that I'm spending a huge amount of my time in PlanarImage.getWidth(), which looks like it's all coming down to RenderedOp having a ton of synchronized methods:

https://jai-core.dev.java.net/source/browse/jai-core/src/share/classes/j...

I'll post here for posterity if I find good workarounds.

jyotigupta.iitd
Offline
Joined: 2012-02-02
Points: 0

I am facing the same problem in my application. Using multiple threads to read images for urls and then doing processing on them. The threads are getting blocked at the JPEGImageDecoder. Did the change to use "ImageRead" operation from ImageIO solve the issue? Is there any operation in ImageIO for creating images from url? Any help is much appreciated.

Thanks,

Jyoti

imagero
Offline
Joined: 2003-11-18
Points: 0

There are few JPEGImageDecoder classes:

com.sun.image.codec.jpeg.JPEGImageDecoder

com.sun.media.jai.codecimpl.JPEGImageDecoder

sun.awt.image.JPEGImageDecoder

May they get blocked due calls to jni?

Brian Burkhalter

On May 15, 2008, at 3:45 PM, jai-interest@javadesktop.org wrote:

> Thanks for your help. I'll try out your suggestions.
>
> Also, in my profiling, I'm finding that I'm spending a huge amount
> of my time in PlanarImage.getWidth(), which looks like it's all
> coming down to RenderedOp having a ton of synchronized methods:

I suspect it is more an artifact of deferred execution.

Brian

> https://jai-core.dev.java.net/source/browse/jai-core/src/share/classes/j...
>
> I'll post here for posterity if I find good workarounds.
> [Message sent by forum member 'atomly' (atomly)]
>
> http://forums.java.net/jive/thread.jspa?messageID=274720
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail: interest-help@jai.dev.java.net
>

>^..^< >^..^<

Brian Burkhalter
Java Imaging and Video
Sun Microsystems, Inc.

This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

atomly
Offline
Joined: 2008-05-14
Points: 0

I'm not entirely sure what you mean by "artifact of deferred execution."

In my load testing, about 27% of the time is spent in

com.sun.media.jai.codec.ImageEncoder.encode

and about 16% is taken in

javax.media.jai.PlanarImage.getWidth

If you're saying that there is some prep-work on PlanarImage that doesn't get executed until the first call into the instance and that happens to be getWidth, I'd believe that, but that's still a huge amount of time spent in there. Especially considering the fact that we can't push our CPU past about 30% no matter how many machines/threads we throw at it.

imagero
Offline
Joined: 2003-11-18
Points: 0

I am just curios, are you using by any chance Solaris?
I asking because I memorize as we has similar problem. The OS seem to think that our java process had nothing to do - jvm just din't get processor time. It worked for a while, then it slept for about one minute and so on. On cheap Win XP system our programm worked all the time with 100% CPU.

imagero
Offline
Joined: 2003-11-18
Points: 0

This is VERY old problem, I faced it about 2000 during my work for pixfind.

We had SUN workstation (if I memorize right - price about $20.000) and out image import programm just didn't get processor time.

Cheap WindowsXP PC had 10 times better performance.

Bob Deen

Sounds like a cool usage! Do you have a URL?

> I'm using JAI for the WikiSky project. The code is running on quad
> core systems. I noticed that JAI functions utilize only two cores
> at a time. In other words, no matter how many threads are running,
> the quad-core CPU utilization is balancing at 50%.
> Is there any settings in JAI to use all available cores in parallel?

The TileScheduler has setParallelism() and setPrefetchParallelism(),
the default for which (interestingly enough) is 2.

Now, you may have to schedule tiles rather than simply requesting
them to get the parallelism to work, but it definitely does. That's
how JadeDisplay works... it schedules tiles for background
computation, then renders them as they become available.

Hope that helps...

-Bob

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

klink
Offline
Joined: 2008-04-17
Points: 0

Hi Bob,

Looks like exactly what I need. I'll play with those parameters tonight. Thanks.
The URL of the project is http://www.wikisky.org

I have few more questions regarding tiled and multiple scale levels processing optimization. I'll post it bit later.

Sergei