lstipakov
lstipakov

Reputation: 3238

Android SHA1 is painfully slow

Am I doing it wrong, or Android's JVM implementation of SHA1 is painfully slow? My code is below:

in = new FileInputStream("/mnt/sdcard/200mb");
MessageDigest digester = MessageDigest.getInstance("sha1");
byte[] bytes = new byte[8192];
int byteCount;
int total = 0;
while ((byteCount = in.read(bytes)) > 0) {
    total += byteCount;
    digester.update(bytes, 0, byteCount);
    Log.d("sha", "processed " + total);
}    

and here is log:

10-31 13:59:53.790 D/sha     ( 3386): processed 4931584
10-31 13:59:54.790 D/sha     ( 3386): processed 5054464
10-31 13:59:55.780 D/sha     ( 3386): processed 5177344

which is about 100k / sec, for me it is unacceptable.

I am using physical device (LG P990, 2.2.2). Can I get better results with Java, or I have to look into JNI implementation?

I have played with buffer size - no significant difference.

Traceview results

So it seems the bottleneck is in updating hash.

enter image description here

Research

That is interesting. When I have tried on 2.3.2 (SE Xperia), processing speed was about 12meg/sec. When I've tried on 2.2 (HTC Legend), the speed was even slower than at first device. Could it be so that something has been changed since 2.3?

Upvotes: 4

Views: 2093

Answers (1)

Martin Nordholts
Martin Nordholts

Reputation: 10358

According to my benchmarks, that code should easily be able to perform way better than 120 kb/s (I'm running on different hardware, but still).

If you profile the code with Traceview, where is the time spent? If the bottleneck is FileInputStream.read(), think about:

  • if some other app is using the sdcard at the same time as you, like a media indexing app or something. Sharing bandwidth with some other app will have an adverse effect on the sdcard reading performance of your app.
  • If the sdcard itself is the problem. Try another sdcard or re-format the one you have.

If the bottleneck is MessageDigest.update() (which I doubt), I guess you do need to look into a JNI solution. For your information, the SHA-1 implementation already is in native code (see android_message_digest_sha1.cpp), but maybe you can gain a speedup by avoiding some native <-> Java copying.

Update 1 (Please ignore):

(Based on your profiling, the problem seems to be that you don't use Android's optimized android.security.MessageDigest but instead java.security.MessageDigest. Try android.security.MessageDigest instead. Both Android 2.2 and 2.3 have native SHA-1 implementations of android.security.MessageDigest.)

Update 2:

Sorry, I forgot about android.security.MessageDigest being internal. I now realize that I was also using java.security.MessageDigest in my benchmarking. I was running on Android 2.3 though, and it turns out the SHA-1 implementation of java.security.MessageDigest in Android 2.3 is in native code as well, while that appearently is not the case on Android 2.2.

So the answer to your original question is: Yes, it is painfully slow in Android 2.2 due to a Java implementation but significantly faster in Android 2.3 due to an implementation in native code. You should see similar speedups on Android 2.2 if you use your own SHA-1 implementation in native code.

Upvotes: 4

Related Questions