【问题标题】:Java BigInteger source code performance benchmark [duplicate]Java BigInteger 源代码性能基准测试 [重复]
【发布时间】:2021-11-15 13:43:34
【问题描述】:

我试图弄清楚为什么 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 中完成了所有操作,结果完全相同。如果源代码/算法完全相同,为什么这个基准测试会有如此大的差异?

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

【问题讨论】:

    标签: java performance math benchmarking biginteger


    【解决方案1】:

    一些,甚至可能是大多数,JVM 有许多内在函数,而不是 Java 代码,用于各种计算密集型操作。更多详细信息可以在this question 的答案中找到。其中一个内在函数 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 类的各种编译器/运行时优化,这些优化不适用于自定义实现。

    【讨论】:

    • 谢谢,这看起来像是我正在寻找的答案。这是否意味着不可能实现与内置实现具有相似速度的自己的算法?至少有了这个 jvm arg,我可以进行基准测试,以确保它尽可能接近。
    猜你喜欢
    • 2017-05-29
    • 2014-07-30
    • 2014-12-19
    • 2020-09-27
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    相关资源
    最近更新 更多