Android Runtime vs NDK performance

While developing a game engine for Android, I was confident that native C / C ++ code would execute faster than similar Java code. This statement is true, but not for the latest versions of Android. To check why this is happening, I decided to do a little research.





For the test, Android Studio 4.1.3 was used - for Java Android SDK (API 30), for C / C ++ Android NDK (r21, CLang compiler). The test is pretty dumb that does arithmetic operations on an int array in two nested loops. Nothing meaningful or specific.





Here is a method written in Java:





public void calculateJava(int size) {
    int[] array = new int[size];
    int sum = 0;

    for (int i=0; i<size; i++) {
        array[i] = i;
        for (int j=0; j<size; j++) {
            sum += array[i] * array[j];
            sum -= sum / 3;
       }
    }    
 }
      
      



C/C++ ( Java GC):





extern "C" JNIEXPORT void JNICALL Java_com_axiom_firstnative_MainActivity_calculateNative(
        JNIEnv* env,
        jobject,
        jint size) {

    int* array = new int[size];
    int sum = 0;

    for (int i=0; i<size; i++) {
        array[i] = i;
        for (int j=0; j<size; j++) {
            sum += array[i] * array[j];
            sum -= sum / 3;
        }
    }

    // delete[] array;
}

      
      



, Java:





     long startTime = System.nanoTime();
     calculateNative(4096);
     long nativeTime = System.nanoTime() - startTime;
                
     startTime = System.nanoTime();
     calculateJava(4096);
     long javaTime = System.nanoTime() - startTime;
                
     String report = "VM:" + System.getProperty("java.vm.version")
                        + "\n\nC/C++: " + nativeTime 
                        + "ns\nJava: " + javaTime + "ns\n"
                        + "\nJava to C/C++ ratio " 
                        + ((double) javaTime / (double) nativeTime);
      
      



Samsung Galaxy Tab E (Android 4.4.4) :

Java time: 2 166 748 ns

C/C++ time: 396 729 ns (C/C++ 5 )





Prestigio K3 Muze (Android 8.1):

Java time: 3 477 001ns ( )

C/C++ time: 547 692ns (C/C++ 6 ),

Java 30-40% (?).





Samsung Galaxy S21 Ultra (Android 11):

Java time: 111 000ns

C/C++ time: 121 269ns

: Java 9% 40-50% C/C++ .





CLang (-O3)  C/C++ ~30-35% (Prestigio K3 Muze Android 8.1) Java , .





Smasung Galaxy S21 Ultra (Android 11) Java 10-20% /C++ CLang (-O3). ...





p.s. , , CPU.





, Java Android C/C++ ? ?

. Android Runtime Ahead-of-Time Java , Just-In-Time . . :





The JIT compiler complements ART's current ahead-of-time (AOT) compiler and improves runtime performance. Although JIT and AOT use the same compiler with a similar set of optimizations, the generated code might not be identical. JIT makes use of runtime type information can do better inlining and makes on stack replacement (OSR) compilation possible, all of which generate slightly different code.





Java NDK C/C++ ?

As it seems to me, for old devices with a Dalvik VM virtual machine (up to Android 7.0) - definitely yes. As for newer devices, with Android versions higher than 7.0 (where the ART runtime is used), this does not make much sense, unless you are an experienced C / C ++ developer who deeply understands how the CPU works and is able to make optimizations better than the Android Runtime. And the game is not worth the candle (effect / effort), except for the following cases:





  • You are porting an existing C / C ++ application to Android





  • You want to use C / C ++ libraries not available from Java





  • You want to use APIs not available in the Android SDK





PS If you have any thoughts, I will be glad to comment.








All Articles