Android Runtime 如何比 CLang C/C++ 编译器 (Android NDK) 更高效地编译 Java?

How Android Runtime compiles Java more efficiently than the CLang C/С++ compiler (Android NDK)?

我绝对确定 C\C++ 本机代码 运行 比 Java 代码快。它是。我的简单 C/C++ 基准测试(对 int 数组的随机算术运算)运行s 比旧平板电脑上的相同 Java 代码快 5-7 倍(Samsung Galaxy Tab E - Android 4.4.4 - Dalvik VM),但在最近使用 ART Prestigio K3 Muze (Android 8.1) 和 Samsung S21 Ultra (Android 11) 的设备上速度较慢。

为什么 Android 运行时编译代码 运行 比原生 C/C++ 代码(Android NDK / JNI)快 运行s?

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;
}

单击时 (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 时间:2166748ns,C/C++ 时间:396729 ns(C/C++ 5 次更快)

但是

Prestigio K3 Muze (Android 8.1) 首次启动 - Java time:3477001ns, C/C++ 时间:547692ns (C/C++ 6倍),但在预热后 Java 运行s 快 30-40%。

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

打开 CLang 编译器优化选项 (-O3) 使 C/C++ 运行 ~30-35% (Android 8.1) 比 Android 运行时优化 Java 代码。但是,在 Android 11 ART 优化代码 运行 上比 CLang C/C++ 优化 (-O3) 本机代码 快 10-20% .这是令人兴奋的...

p.s。两个基准测试 运行 在一个线程上按顺序进行,所以我想它们使用相同的内核。

问题:

如何Android运行时编译比CLang编译器更高效的本地代码?

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

如何Android运行时编译比CLang(AndroidNDK)更高效的本地代码C/C++编译器?

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.

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

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

上快 ~10-20%

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

结论: 以我的拙见,为最近的 Android 设备(从 v7.0 Nougat - ART VM 开始)编写 C/C++ 代码没有性能优势,除非你是一个有经验的 C/C++ 开发人员并深入了解 CPU 体系结构,因此您可以比 Android 运行时更好地进行优化。

此外,Android NDK (C/C++) 仍然是 Android 开发人员的唯一途径:

  1. 将您的原生 C/C++ 代码移植到 Android。
  2. 使用 C/C++ 游戏引擎和库(如 Vulkan 或 TensorFlow)。
  3. 使用 Android SDK 中不可用的平台特定 API。