Java BigInteger 源代码性能基准

Java BigInteger source code performance benchmark

我想弄清楚为什么 Java 的 BigInteger 乘法基准始终比使用从 BigInteger.java 源代码复制到我的项目的实例快 3 倍。使用 jmh 运行 基准。这是一个示例输出,请注意加法 运行 大致相同。

Benchmark                                 Mode  Cnt       Score       Error  Units
BenchmarkTest.javaBigInteger_add         thrpt    5  856062.338 � 34040.923  ops/s
BenchmarkTest.sourceBigInteger_add       thrpt    5  842421.746 � 39630.112  ops/s
BenchmarkTest.javaBigInteger_multiply    thrpt    5  525649.635 � 15271.083  ops/s
BenchmarkTest.sourceBigInteger_multiply  thrpt    5  133944.766 �  1832.857  ops/s

我这样做的原因是试图将其中的一部分移植到 Kotlin 我注意到基准测试有点慢。为了查看它是否与 Kotlin 有关,我将其从图片中删除并在纯 java 中执行所有操作,结果完全相同。如果来源 code/algorithms 完全相同,为什么这个基准会有如此大的差异?

使用此代码的项目:https://github.com/asheragy/BigInteger-Benchmark

一些,甚至可能是大多数,JVM 有许多内部函数,这些函数代替 Java 代码用于各种计算密集型操作。可以在 的答案中找到更多详细信息。其中一个内在函数 multiplyToLen 专门处理 BigInteger 乘法。

通过更改 build.gradle 文件中的 jmh 配置禁用此内部函数后,如下所示:

jmh {
    warmupIterations = 2 
    iterations = 5 
    fork = 1 
    jvmArgsPrepend = ['-XX:+UnlockDiagnosticVMOptions', '-XX:-UseMultiplyToLenIntrinsic']
}

我在 x86-64 架构上的 OpenJDK 11 (JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+8-jvmci-21.1-b05) 上得到以下乘法基准测试结果:

Benchmark                        Mode  Cnt       Score      Error  Units
BenchmarkTest.javaBigInteger    thrpt    5  107476.070 ± 8059.020  ops/s
BenchmarkTest.sourceBigInteger  thrpt    5  108011.737 ± 7105.221  ops/s

这几乎完全消除了两种实现之间的差距。

可能还有其他配置选项的作用较小,但我认为总的来说,答案是针对标准 JDK 类 进行了各种 compiler/runtime 优化不适用于自定义实现。