Here’s an interesting find, I came upon recently.
In the the process of moving an Android app project of mine, Camverter, off the now ageing version r10e of the Android NDK and onto version r18b, I had to rebuild some of its dependencies as well, in order to to maintain standard library compatibility.
In r18b GCC has been removed, in favour of Clang, so I decided I wanted to gauge any performance differences, that that change might have incurred. One such dependency is Tesseract, which is a main part of the OCR pipeline of the app.
In this post we’ll be looking at how it performs, with versions built by both compilers.
Build
To build an Android compatible shared library of Tesseract, I’m using a homegrown build system based on Docker, aptly named Building for Android with Docker, or bad for short. I won’t go into details about that project here, but feel free to check it out nonetheless.
The docker files I’ve used for each version of the NDK is linked here:
- Version r10e: tesseract-3.05.02.Dockerfile
- Version r18b: tesseract-3.05.02.Dockerfile
Aside from using different NDKs and a few minor changes to the configure flags, they’re pretty much alike.
To note, in both cases the optimisation level of GCC was set to -O2:
root@3495122c4fa2:/tesseract-3.05.02# grep CXXFLAGS Makefile CXXFLAGS = -g -O2 -std=c++11 |
Testing
To benchmark the performance of tesseract, I’ve added a very simple test that runs OCR on the same 640×480 black and white test image, ten times in a row1, and then outputs the average running time:
Full source of the test available here.
Test devices
Currently the range of my own personal device lab, only extends to the following two devices. It’s not extensive, but given their relative difference in chipset, I think they’ll provide an adequately varied performance insight:
- Sony Xperia XZ1 Compact (Snapdragon 835 running Android 9).
- Samsung Galaxy S5 G900F (Snapdragon 801 running Android 6.01).
Results
In the chart below it’s apparent, that there’s a significant performance increase to be gained, by switching from GCC to Clang.
This roughly translates into a 28.3% reduction for the Samsung, and a whopping 38.7% decrease for the Sony. Thank you very much Sir Clang!
Bonus
Additionally I decided to run a similar test for version 4.0.0 (non lstm) of Tesseract as well. The test source and Dockerfile for building v4.0.0 is likewise available in the bad repository.
In this instance however, I simply couldn’t get a successful build with r10e, hence I only have numbers for Clang.
Once again, there’s a handy performance increase to be had.
Comparison
Execution time reduction for v4.0.0 (r18b / Clang), compared to v3.05.02:
r10e | r18b | |
---|---|---|
S5 | 39.2% | 15.3% |
XZ1 | 50.5% | 19.3% |
That’s a 2X increase in performance, in the case of the Sony, going from v3.05.02 compiled with GCC to v4.0.0 compiled with Clang.
That is pretty awesome, and I’m sure users of the app will welcome the reduced battery drain.
Footnotes
- I believe I got this image originally from the Tesseract project itself, but I’ve failed to find the source.