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 完全相同,为什么这个基准会有如此大的差异?
一些,甚至可能是大多数,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 优化不适用于自定义实现。
我想弄清楚为什么 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 完全相同,为什么这个基准会有如此大的差异?
一些,甚至可能是大多数,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 优化不适用于自定义实现。