Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / October 2007

Tip: Looking for answers? Try searching our database.

JAI optimizing..

Thread view: 
a0a - 24 Sep 2007 19:15 GMT
Hi everyone,

I did a little benchmark on the speedup that JAI can bring in
computing the point with minimum distance from a given source point
(x,y) out of an array of x,y coordinates.

I did this both with JAI and by brute-forcing it using a simple
distance check. Although the JAI is very elegant in that it
automatically returns ALL minimum distance points, it is also 6 times
slower than the brute-force method.

I am guessing that I may have gotten something wrong in the set-up,
but since the information on JAI and tutorials are rather scarce or
not working at all, I thought maybe someone here could take a look at
this:

------ this is what I want to do ------

ArrayList<Integer> indexes = new ArrayList<Integer> ();
int closestPoint = Integer.MAX_VALUE;

for (int i = 0; i < xvalues.length; i++)
{
    int xdiff = xvalues[i] - x;
    int ydiff = yvalues[i] - y;
    int sqr = xdiff* xdiff + ydiff*ydiff;
    if ( sqr == closestPoint )
    {
        indexes.add(i);
    }
    if ( sqr < closestPoint )
    {
        closestPoint = sqr;
        indexes.clear();
        indexes.add(i);
    }
}

------ this is what does it, but 6 times slower, in JAI ------

double[] xSub = new double[]{x};
double[] ySub = new double[]{y};

RenderedOp renderedOpXSubXRef = SubtractConstDescriptor.create(imageX,
xSub, rh);
RenderedOp renderedOpYSubYRef = SubtractConstDescriptor.create(imageY,
ySub, rh);
RenderedOp renderedOpXDiff2 =
MultiplyDescriptor.create(renderedOpXSubXRef, renderedOpXSubXRef, rh);
RenderedOp renderedOpYDiff2 =
MultiplyDescriptor.create(renderedOpYSubYRef, renderedOpYSubYRef, rh);
RenderedOp renderedOpSum = AddDescriptor.create(renderedOpXDiff2,
renderedOpYDiff2, rh);
RenderedOp renderedOpExtrema = ExtremaDescriptor.create(renderedOpSum,
null, 1, 1, true, 1, rh);

List minLocations =
((List[])renderedOpExtrema.getProperty("minLocations"))[0];

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

Of course, right before this code I convert the 2 int[] arrays
containing x values and y values into BufferedImages using a GrayScale
colorspace, 32 bit colorModel with no alpha, no transparency, no
premultiplication. I do not alter the rasters during computation, I
merely fetch the min values from the list "minLocations" afterwards.
Timing it indicates that processing is extremely slow, however, I
still have to rewrite the benchmark to warm up first and redo the test
a number of times, maybe the test may show improvement. However, if
anyone has ideas how to speed up the operation pipe, I am all ears!
a0a - 25 Sep 2007 13:36 GMT
Warming up the test seems to make a huge difference.  The first
RenderedOp takes about 6 times longer than the whole pojo processing,
but each additional RenderedOp takes only fractions of the total time,
leading me to believe the set-up of JAI is slow, but processing is
extremely fast once you have all the system resources set-up. I
achieved almost a 100 fold speed increase for processing 5 million
coordinates, compared to pojo.

I dived a little deeper in the JAI docs, and essentially tried to
rewrite the setup using RenderableOp and ParameterBlock's instead of
RenderedOp. I got it to compile correctly, but during runtime, I get
an exception that got me rather puzzled:

Exception in thread "main" com.sun.medialib.mlib.mediaLibException:
mediaLib: exception in a native method.
    at com.sun.medialib.mlib.Image.ExtremaLocations(Native Method)
    at
com.sun.media.jai.mlib.MlibExtremaOpImage.accumulateStatistics(MlibExtremaOpImage.java:
170)
    at
javax.media.jai.StatisticsOpImage.getProperty(StatisticsOpImage.java:
292)
    at
com.sun.media.jai.opimage.ExtremaOpImage.getProperty(ExtremaOpImage.java:
100)
    at javax.media.jai.RenderedOp$1.getProperty(RenderedOp.java:1808)
    at
javax.media.jai.PropertyEnvironment.getProperty(PropertyEnvironment.java:
197)
    at
javax.media.jai.PropertySourceImpl.getProperty(PropertySourceImpl.java:
277)
    at
javax.media.jai.WritablePropertySourceImpl.getProperty(WritablePropertySourceImpl.java:
130)
    at javax.media.jai.RenderedOp.getProperty(RenderedOp.java:1982)
    at JAIDistanceTest.testDistances2(JAIDistanceTest.java:180)
    at JAIDistanceTest.<init>(JAIDistanceTest.java:71)
    at JAITest.main(JAITest.java:40)

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

And here is the code I used, maybe someone can spot the obvious
mistake? Thanks!

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

int bits[] = new int[] {32};
ColorSpace     colorSpace    = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorModel     colorModel     = new ComponentColorModel(colorSpace, bits,
false, false, Transparency.OPAQUE, DataBuffer.TYPE_INT);
SampleModel     sampleModel    =
colorModel.createCompatibleSampleModel(25,25);;

DataBufferInt   dataBufferX     = new DataBufferInt(xvalues,
xvalues.length);
WritableRaster     rasterX        =
WritableRaster.createWritableRaster(sampleModel, dataBufferX, new
Point(0,0));
BufferedImage     imageX         = new BufferedImage(colorModel, rasterX,
false, null);

DataBufferInt   dataBufferY     = new DataBufferInt(yvalues,
yvalues.length);
WritableRaster     rasterY        =
WritableRaster.createWritableRaster(sampleModel, dataBufferY, new
Point(0,0));
BufferedImage     imageY         = new BufferedImage(colorModel, rasterY,
false, null);

PlanarImage    planarImageX    = new RenderedImageAdapter(imageX);
PlanarImage    planarImageY    = new RenderedImageAdapter(imageY);

RenderingHints renderingHints     = new
RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
renderingHints.put(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
renderingHints.put(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
renderingHints.put(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
renderingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);

// create a renderable image with no downsampled piramid
ParameterBlock     parameterBlockX = new ParameterBlock();
parameterBlockX.addSource(planarImageX);
parameterBlockX.add(null).add(null).add(null).add(null).add(null);
RenderableImage renderableImageX = JAI.createRenderable("renderable",
parameterBlockX);

// create a renderable image with no downsampled piramid
ParameterBlock     parameterBlockY = new ParameterBlock();
parameterBlockY.addSource(planarImageY);
parameterBlockY.add(null).add(null).add(null).add(null).add(null);
RenderableImage renderableImageY = JAI.createRenderable("renderable",
parameterBlockY);

double[] xSub = new double[]{x};
double[] ySub = new double[]{y};

long nanoStart = System.nanoTime();
ParameterBlock     parameterBlockSub1         = new ParameterBlock();
        parameterBlockSub1.addSource(renderableImageX);
        parameterBlockSub1.add(xSub);
RenderableOp renderableOpXSubXRef        =
JAI.createRenderable("subtractconst", parameterBlockSub1);

ParameterBlock     parameterBlockSub2         = new ParameterBlock();
        parameterBlockSub2.addSource(renderableImageY);
        parameterBlockSub2.add(ySub);
RenderableOp     renderableOpYSubYRef        =
JAI.createRenderable("subtractconst", parameterBlockSub2);

ParameterBlock     parameterBlockPow1         = new ParameterBlock();
        parameterBlockPow1.addSource(renderableOpXSubXRef);
        parameterBlockPow1.addSource(renderableOpXSubXRef);
RenderableOp     renderableOpXDiff2            = JAI.createRenderable("multiply",
parameterBlockPow1);

ParameterBlock     parameterBlockPow2         = new ParameterBlock();
        parameterBlockPow2.addSource(renderableOpYSubYRef);
        parameterBlockPow2.addSource(renderableOpYSubYRef);
RenderableOp     renderableOpYDiff2            = JAI.createRenderable("multiply",
parameterBlockPow2);

ParameterBlock     parameterBlockSum         = new ParameterBlock();
        parameterBlockSum.addSource(renderableOpXDiff2);
        parameterBlockSum.addSource(renderableOpYDiff2);
RenderableOp     renderableOpSum            = JAI.createRenderable("add",
parameterBlockSum);

        AffineTransform screenResolution = new AffineTransform();
        RenderContext renderContext     = new
RenderContext(screenResolution);
RenderedOp     renderedOpExtrema        =
ExtremaDescriptor.create(renderableOpSum.createRendering(renderContext),
null, 1, 1, true, 1, renderingHints);

long nanoEnd = System.nanoTime();

List minLocations =
((List[])renderedOpExtrema.getProperty("minLocations"))[0];

some good references in case you are interested:

http://72.5.124.55/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/Progr
amming-environ.doc.html#55932

http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/Imag
e-manipulation.doc.html#56366

http://java.sun.com/j2se/1.3/docs/api/java/awt/image/renderable/RenderableImage.html
(JAI API docs)
http://www.geocities.com/larryhr/samplecode/samplecode.html (sample
code)
http://forums.java.net/jive/thread.jspa?messageID=235530&tstart=0
(chained calls)
http://java.sun.com/products/java-media/jai/forDevelopers/jaifaq.html
(sun tutorials)

> Hi everyone,
>
[quoted text clipped - 67 lines]
> a number of times, maybe the test may show improvement. However, if
> anyone has ideas how to speed up the operation pipe, I am all ears!
Andrew Thompson - 25 Sep 2007 14:11 GMT
...
>And here is the code I used, maybe someone can spot the obvious
>mistake?

1) Posting code snippets* to an uncommon API that nobody
else** can easily compile and run?
2) Top-posting your reply to an earlier post (does not make
people well disposed to helping).  It is considered better,
and clearer, to post 'in-line, with trimming'.

* Much more chance of help, with an SSCCE.
<http://www.physci.org/codes/sscce.html>
** No, I myself have never dealt with JAI, but to get
the attention and help of those that have, your best
bet is to make it easy for them.

Signature

Andrew Thompson
http://www.athompson.info/andrew/

a0a - 04 Oct 2007 17:06 GMT
> 1) Posting code snippets* to an uncommon API that nobody
> else** can easily compile and run?

I asked a question was about the proper use of the JAI API. I was
simply hoping someone with JAI knowledge could spot an obvious error.
I could have omitted the code, and fantasized about openGL and
directX, but it so happens it wouldn't have helped me a great big deal
either in this case.

JAI, tutorials, docs and examples can be downloaded freely by the way,
so this is not something which "nobody else can easily compile and
run". And to my taste, that wasn't the reason why I included the code
in the first place. I was just trying to give readers an idea about
the sort of thing I was doing. People proficient in JAI would
certainly get it.

> 2) Top-posting your reply to an earlier post (does not make
> people well disposed to helping).  It is considered better,
[quoted text clipped - 5 lines]
> the attention and help of those that have, your best
> bet is to make it easy for them.

Fair enough, I was not aware I was causing difficult. I am posting
through Google Groups, which makes it look ok while posting. My
biggest problem was not that the code would not run, as it did. The
problem is that JAI documentation is rather sketchy at best. Do a
search on com.sun.medialib.mlib.mediaLibException and you will catch
my drift.

To give you at least something to take away from this discussion, JAI
performed rather bad, compared to native c/c++ using Intel's IPP
library, which is the clear winner in this case. JAI was about 200
times slower, and that includes JNI overhead. Still, JAI was about 100
times faster than the pojo algo described previously, contrary to what
I said in my original post. The trick was indeed to warm up the JAI
pipe before testing, and then lock the dimensions of the
BufferedImage, as this would otherwise cause the library to re-
allocate temporary storage.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.