Desempenho do Android Runtime vs NDK

Ao desenvolver um mecanismo de jogo para Android, estava confiante de que o código C / C ++ nativo seria executado mais rápido do que o código Java semelhante. Esta afirmação é verdadeira, mas não para as versões mais recentes do Android. Para verificar por que isso está acontecendo, decidi fazer uma pequena pesquisa.





Para o teste, foi usado o Android Studio 4.1.3 - para Java Android SDK (API 30), para C / C ++ Android NDK (r21, compilador CLang). O teste é muito burro, pois faz operações aritméticas em uma matriz int em dois loops aninhados. Nada significativo e específico.





Aqui está um método escrito em 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++ ?

Parece-me que para dispositivos antigos com uma máquina virtual Dalvik VM (até Android 7.0) - definitivamente sim. Quanto aos dispositivos mais recentes, com versões do Android superiores a 7.0 (onde o tempo de execução ART é usado), isso não faz muito sentido, a menos que você seja um desenvolvedor C / C ++ experiente que entenda profundamente como a CPU funciona e seja capaz de fazer otimizações melhores do que o Android Runtime. E o jogo não vale a pena (efeito / esforço), exceto nos seguintes casos:





  • Você está transferindo um aplicativo C / C ++ existente para o Android





  • Você deseja usar bibliotecas C / C ++ não disponíveis em Java





  • Você deseja usar APIs não disponíveis no Android SDK





PS: Se você tiver alguma opinião, terei todo o prazer em comentar.








All Articles