Profiling applications can be fun. For the last few days I’m working constantly on my final year project and one day I have decided to do quite a strange thing. As my application client (MIDP application) has to display a map and it makes heavy use of web services I have designed and implemented a web service which provides the map tiles for the mobile phone. To cut a long story short main performance bottelneck was to convert an image into byte array and send it over the network as a SOAP message. What my application server does is to cut large image 1024×1024 into small tiles 16×16 pixels and serve them as byte arrays (actually Base64 strings).
As the client is a mobile application all the processing of the image is done on the server side. The speed of such an implementation depends on 3 things, first we have to create the tile, download it and create the image from downloaded data. Guess what? The slowest part of the whole process was to create the tile on the server side!!!.
Just for testing, creating 64×64 matrix of tiles took about 28 fat long seconds on my 2.0 GHz dual core 2GB RAM laptop which of course is unacceptable.
Looking here and there I started profiling to find out where is the main bottelneck.
The main problem with this application is the MIDP, which does its job but unfortuntelly supports only PNG format. This limitation leads to another problem, ImageIO class writes PNG as slow as snails. I have created and profiled three methods to see the difference, in all of them I use same PNG image 1024×104 read before convertion into BufferedImage object, first method:
public byte[] testImageIO(){
try {
baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return baos.toByteArray();
}
This method with mentioned image size (format .png) takes about 1800 ms to convert. Same method but with “jpeg” attribute inside write method of ImageIO takes about 550 ms (you can see the difference already). As mentioned above althought this cannot be used for my application as I get exception on the client side converting it back into image.
I was looking quite a long time on the internet before I’ve found the answer to my troubles.
Here you have thrid method which uses JPEGImageEncoder to do the converstion:
public byte[] testJPEGEncoder() {
try {
baos = new ByteArrayOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(baos);
encoder.encode(image);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (ImageFormatException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return baos.toByteArray();
}
Guess what!? It still works on my mobile side, it is called JPEGImageEncoder and does no harm to my bytes along the way, but as we are talking about performance here the result from Netbeans profiler is…….
Take a deep breath!
230 ms!
From 18000 ms to 230 ms! Never go back to ImageIO! 😉