Android Runtime vs performances NDK

Lors du développement d'un moteur de jeu pour Android, j'étais convaincu que le code C / C ++ natif s'exécuterait plus rapidement que le code Java similaire. Cette affirmation est vraie, mais pas pour les dernières versions d'Android. Pour vérifier pourquoi cela se produit, j'ai décidé de faire un peu de recherche.





Pour le test, Android Studio 4.1.3 a été utilisé - pour Java Android SDK (API 30), pour C / C ++ Android NDK (r21, compilateur CLang). Le test est assez stupide et effectue des opérations arithmétiques sur un tableau int en deux boucles imbriquées. Rien de significatif et de spécifique.





Voici une méthode écrite en 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++ ?

Il me semble que pour les anciens appareils avec une machine virtuelle Dalvik VM (jusqu'à Android 7.0) - certainement oui. En ce qui concerne les appareils plus récents, avec des versions d'Android supérieures à 7.0 (où le runtime ART est utilisé), cela n'a pas beaucoup de sens, à moins que vous ne soyez un développeur C / C ++ expérimenté qui comprend profondément le fonctionnement du processeur et est capable de faire optimisations meilleures que le Runtime Android. Et le jeu ne vaut pas la chandelle (effet / effort), sauf dans les cas suivants:





  • Vous portez une application C / C ++ existante sur Android





  • Vous souhaitez utiliser des bibliothèques C / C ++ non disponibles à partir de Java





  • Vous souhaitez utiliser des API non disponibles dans le SDK Android





PS Si vous avez des idées, je serai heureux de commenter.








All Articles