Android运行时如何比CLang C/С++编译器(Android NDK)更有效地编译Java? [英] How Android Runtime compiles Java more efficiently than the CLang C/С++ compiler (Android NDK)?

查看:76
本文介绍了Android运行时如何比CLang C/С++编译器(Android NDK)更有效地编译Java?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我绝对确定C \ C ++本机代码将比Java代码运行得更快.是的.我的简单C/C ++基准(在int数组上进行随机算术运算)的运行速度比旧平板电脑(三星Galaxy Tab E-Android 4.4.4-Dalvik VM)上的相同Java代码快5-7倍,但在具有以下功能的最新设备上运行速度较慢ART Prestigio K3 Muze(Android 8.1)&三星S21 Ultra(Android 11).

I was absolutely sure that C\C++ native code will run faster than Java code. And it is. My simple C/C++ benchmark (random arithmetic operations on int array) runs 5-7 times faster than the same Java code on an old tablet (Samsung Galaxy Tab E - Android 4.4.4 - Dalvik VM), but slower on recent devices with ART Prestigio K3 Muze (Android 8.1) & Samsung S21 Ultra (Android 11).

为什么Android Runtime编译的代码比本机C/C ++代码(Android NDK/JNI)运行得更快?

Why Android Runtime compiled code runs faster than native C/C++ code (Android NDK / JNI)?

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 ++代码(JNI):

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

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

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

    // delete[] array;
}

OnClick(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);

结果:

三星Galaxy Tab E(Android 4.4.4)-Java时间:2166748ns,C/C ++时间:396729 ns(C/C ++快5倍)

Samsung Galaxy Tab E (Android 4.4.4) - Java time: 2166748ns , C/C++ time: 396729 ns (C/C++ 5 times faster)

但是

Prestigio K3 Muze(Android 8.1)首次启动-Java时间:3477001ns,C/C ++时间:547692ns(C/C ++快6倍),但预热后Java的运行速度提高了30-40%.

Prestigio K3 Muze (Android 8.1) on first start - Java time:3477001ns, C/C++ time: 547692ns (C/C++ 6 times faster), but after warm up Java runs 30-40% faster.

Samsung Galaxy S21 Ultra(Android 11)-Java时间:111000ns,C/C ++时间:121269ns( Java首次启动时快9%,预热后快40-50%!)

Samsung Galaxy S21 Ultra (Android 11) - Java time: 111000ns, C/C++ time: 121269ns (Java 9% faster on first start and 40-50% faster after warm up!!!)

打开CLang编译器优化选项(-O3),使C/C ++(Android 8.1)的运行速度比Android Runtime优化的Java代码快约30-35%.但是,在 Android 11 ART优化的代码上,运行速度比CLang C/C ++优化的(-O3)本机代码快10-20%.真是令人难以置信...

Turning on CLang compiler optimization options (-O3) makes C/C++ run ~30-35% faster (Android 8.1) than Android Runtime optimized Java code. But still, on Android 11 ART optimized code runs 10-20% faster than CLang C/C++ optimized (-O3) native code. That is mind-blowing...

p.s.这两个基准在一个线程上按顺序运行,因此我想它们使用相同的内核.

p.s. Both benchmarks run sequentially on one thread, so I suppose they use the same core.

问题:

Android Runtime如何比CLang编译器编译更有效的本机代码?

How Android Runtime compile more efficient native code than CLang compiler?

在最新的Android OS版本上编写本机C/C ++代码是否有性能优势?

Is there any performance advantage in writing native C/C++ code on recent Android OS versions?

推荐答案

Android运行时如何比CLang(Android NDK)C/C ++编译器更有效地编译本机代码?

JIT编译器补充了ART当前的提前(AOT)编译器并提高了运行时性能.

The JIT compiler complements ART's current ahead-of-time (AOT) compiler and improves runtime performance.

尽管JIT和AOT使用相同的编译器,但具有类似的设置优化,生成的代码可能不相同.准时制使用运行时类型信息可以更好地进行内联,并进一步可以进行堆栈替换(OSR)编译,所有这些都会生成代码略有不同.

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.

在最新的Android OS版本上编写本机C/C ++代码是否有性能优势?

对于旧的Android设备绝对可以.旧的Android设备使用Dalvik VM来解释代码.Java代码将比Dalvik VM上的相同C/C ++代码慢5-7倍.但是在ART上,在大多数情况下,Android运行时配置文件引导的编译会根据应用程序执行统计信息生成效率更高的本机代码,但是Java仍然比Android 8.1和10上的优化C/C ++代码慢约30-35%.在Android 11上快-20%.

Definitely yes for old Android devices. Old Android devices use Dalvik VM that interprets code. Java code will be 5-7 times slower than the same C/C++ code on Dalvik VM. But on ART, in most cases, Android Runtime profile-guided compilation generates much more efficient native code based on application execution statistics, but Java still ~30-35% slower than optimized C/C++ code on Android 8.1 and ~10-20% faster on Android 11.

https://source.android.com/devices/tech/dalvik/jit-compiler

结论:以我的拙见,除非您是经验丰富的C/C ++开发人员并且对CPU架构有深入的了解,否则为最近的Android设备(从v7.0 Nougat-ART VM开始)编写C/C ++代码并没有性能优势.可以比Android Runtime做得更好.

Conclusion: In my humble opinion, there is no performance advantage in writing C/C++ code for recent Android devices (starting from v7.0 Nougat - ART VM), unless you're an experienced C/C++ developer and deeply understand CPU architecture, so you can do optimization much better than Android Runtime does.

此外,Android NDK(C/C ++)仍然是Android开发人员执行以下操作的唯一方法:

Also, Android NDK (C/C++) is still the only way for Android Developers to:

  1. 将您的本机C/C ++代码移植到Android.
  2. 使用C/C ++游戏引擎和库(例如Vulkan或TensorFlow).
  3. 使用Android SDK中不提供的特定于平台的API.

这篇关于Android运行时如何比CLang C/С++编译器(Android NDK)更有效地编译Java?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆