In order to improve the performance of the application, Android began to gradually rewrite critical sections of code from Java (SDK) to C ++ (NDK). The result turned out to be comparable with the fact that I received a couple of decades ago, making assembly inserts into the turbo-patch code.
I do not set myself the task of describing work with the Android NDK - the experience itself is not enough. Those who are interested, it is better to start with
this link.
The purpose of this short article is to give a few numbers, which I obtained experimentally, comparing the execution time of certain functions written in Java and then rewritten in C ++. And, probably, these figures motivate someone to study this question more deeply.
Since my application is related to the processing of photographs, the bottlenecks were cycles of traversing the pixels of the image and certain actions on them. I tested on real devices - Nexus One and Nexus 7 (2012). The results of the experiments (in ms) are tabulated:
Layer overlay (Luminosity mode, color image)
Nexus one | Nexus 7 |
---|
Sdk | NDK | Sdk | NDK |
---|
2563 | 120 | 4850 | 90 |
2122 | 100 | 4520 | 190 |
2162 | 110 | 4330 | 100 |
On average, the speed gain for Nexus One is 21 times, for Nexus 7 it is 36 times.')
Layer overlay (Color Dodge mode, single color)
Nexus one | Nexus 7 |
---|
Sdk | NDK | Sdk | NDK |
---|
2673 | thirty | 5720 | 80 |
2572 | 20 | 6230 | 70 |
2573 | 20 | 6110 | 70 |
On average, the speed gain for the Nexus One is 112 times, for the Nexus 7 it is 82 times.Layer overlay on transparency gradient
Nexus one | Nexus 7 |
---|
Sdk | NDK | Sdk | NDK |
---|
1301 | 321 | 3010 | 470 |
1221 | 330 | 2670 | 620 |
1211 | 300 | 2770 | 610 |
On average, the speed gain for Nexus One is 4 times, for Nexus 7 - 5 times.As you can see, the results differ by one or even two orders of magnitude. I deliberately cited figures in absolute values, so that the real acceleration of work from the use of NDK could be seen. The relatively modest results of the last test are due to the fact that the standard functions of the OpenCV library, which are fairly well optimized, were used to calculate the overlay. Accordingly, this test clearly shows the real acceleration of the application as a whole.
Casually touch the use of the library OpenCV. As I expected, the Java part of the library is a regular wrapper over the NDK. Still, I conducted the above experiments on fairly heavy and long-playing algorithms, such as finding characteristic points in images, grabcut method. The difference in speed between Java and NDK was a maximum of 10%, which can be attributed to inaccuracy, since at that moment I could not get completely identical images.
Update. It’s rather unpleasant to admit one’s own mistakes, but what to do.
So, here is a sample code with which I evaluated the performance of the Java implementation of the OpenCV library:
for (int i=0; i<mat.rows(); i++){ for (int j=0; j<mat.cols(); j++) { double[] matPix = mat.get(i, j); double[] topPix = top.get(i, j); if (matPix[0]+topPix[0]>255){ matPix[0] = 255.; } else { matPix[0] = (255. * matPix[0]) / (256. - topPix[0]); } mat.put(i, j, matPix); } }
We go around pixel by pixel to two matrices of the same size and, depending on the value of the corresponding pixel of the one and the other matrix, we calculate the resulting pixel.
Thanks to the comments in the comments on the article, the code was optimized as follows (monochrome pictures):
int size = mat.cols(); byte[] matPix = new byte[size]; byte[] topPix = new byte[size]; for (int i=0; i<mat.rows(); i++){ mat.get(i, 0, matPix); top.get(i, 0, topPix); for (int j=0; j<size; j++) { int mp = (matPix[j] & 0xFF); int tp = (topPix[j] & 0xFF); if (mp+tp>255){ mp = 255; } else { mp = (255 * mp) / (256 - tp); } matPix[j] = (byte) mp; } mat.put(i, 0, matPix); }
For testing, again, I used real Nexus One and Nexus 7 devices, I also sent 3 megapixel pictures to the input and in either case I wanted to compare the performance of the devices with each other. The results (average, in ms) are tabulated:
| Nexus one | Nexus 7 |
---|
| Sdk | NDK | Sdk | NDK |
---|
No optimization | 35404 | 245 | 22755 | 160 |
With optimization | 340 | 205 | 210 | 120 |
Conclusions everyone can make himself. Code optimization in C ++ was carried out on the same principle as in Java. I do not cite the code, it is of the same type as above.