4

I ported some portions of my Java code to C++ to speed up calculations on Android (this was a physics subroutine). What I found was that the native code runs several times slower than the Java code. I thought maybe something was wrong with the configuration of my project, or maybe with the array handling, so I put a simple loop in the HelloAndroidJni project to test raw speed difference, and got similar results.

Java Code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    /* ...generic boilerplate code... */

    TextView tv = (TextView) findViewById(R.id.sample_text);
    int loopCount = 100000;

    //time the native method
    long ticks = System.nanoTime();
    int result = nativeTest(100000);
    long nativeTime = (System.nanoTime() - ticks) / 100000;

    //time the Java method
    ticks = System.nanoTime();
    result = javaTest(100000);
    long javaTime = (System.nanoTime() - ticks) / 100000;

    //present results
    tv.setText("Native=" + nativeTime + "; Java=" + javaTime);
}

The loop in Java:

int javaTest(int count) {
    int result = 0;
    for (int i = 0; i < count; i++) {
        for (int j = 0; j < 100; j++) {
        result += 34432; result++;
        result -= 34431; result--;
    } }
    return result;
}

And the C++ code:

JNIEXPORT jint JNICALL
Java_com_fringecode_helloandroidjni_MainActivity_nativeTest(
        JNIEnv *env, jobject jThis, jint count) {
    int result = 0;
    for (int i = 0; i < count; i++) {
        for (int j = 0; j < 100; j++) {
            result += 34432; result++;
            result -= 34431; result--;
        } }
    return result;
}

The rest of the project is identical to the HelloAndroidJni sample project. The result of a typical run is Native=2580 ms, Java=195 ms. What could be making the native code run so much slower than the Java?

EDIT: Incidentally, the native code runs much faster than Java on the emulator, but on my phone (LG V20 / Snapdragon 820) the native is much slower.

HypnoToad
  • 76
  • 5
  • 2
    Have you enabled any compiler optimization? – kmkim85 Sep 28 '17 at 01:15
  • No, that was the first thing I thought but searching Google did not suggest any compiler flags I should use. Currently I'm using no flags. Which flags should I be using? – HypnoToad Sep 28 '17 at 01:20
  • Because of JNI call overhead. See here https://stackoverflow.com/questions/13973035/what-is-the-quantitative-overhead-of-making-a-jni-call – Denis Dda Sep 28 '17 at 02:41
  • Maybe it still has been optimized, try to concact the result in the return statement and test again. And @DenisDda, JNI call overhead is less than 1 ms, so that shouldn't be a problem. – Nabin Bhandari Sep 28 '17 at 02:50
  • You should microbenchmark it correctly, the loop might get optimized out of existence. – Passer By Sep 28 '17 at 03:13
  • The problem is neither JNI overhead nor the loop getting optimized out. The time taken for both loops scales linearly with loopCount. The code I posted here was just a test to try to figure out why my actual physics loop was running slower. I'm going to try some more benchmarks with the other ndk samples and see if they also run slower in C. – HypnoToad Sep 28 '17 at 15:14
  • Why are you creating and then discarding a `std::string`? Can't you just use `return env->NewStringUTF("Hello from C++");` instead of wasting an extra dynamic (de)allocation? – Useless Sep 28 '17 at 16:38
  • The NDK does ship a profiling tool: https://developer.android.com/ndk/guides/simpleperf.html – Dan Albert Sep 28 '17 at 16:47
  • @Useless, that was just leftover from the original HelloAndroidJni sample. I removed that bit of code and it does not affect the result. I am updating the code here to reflect the changes. – HypnoToad Sep 28 '17 at 18:08

1 Answers1

2

Java on the fly optimization may make your loop be as fast as native. On the other hand, without APP_OPTIM=release the C++ compiler will generate debug unoptimized code.

The takeaway is that actually number crunching in Java may be quite efficient, if coded in disciplined manner. But after all, coding same efficiently in C also requires discipline.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Thanks, this was exactly the problem. I did not expect the debug build to slow the native code down so much more than the Java code! – HypnoToad Sep 29 '17 at 00:20