为什么Rust中的对数比Java中的对数慢?

为什么Rust中的对数比Java中的对数慢?,java,floating-point,rust,microbenchmark,jmh,Java,Floating Point,Rust,Microbenchmark,Jmh,如果我在Rust中运行这些基准测试: #[工作台] fn工作台(b:和多台工作台){ 设mut rng=rand::weak_rng(); b、 国际热核实验堆(| | rng.gen_范围::(2.0100.0)); } #[法官席] fn台架(b:和多台台架){ 设mut rng=rand::weak_rng(); b、 国际热核实验堆(| | rng.gen_范围::(2.0100.0).ln()); } 结果是: 测试测试::测试台\u ln。。。试验台:121纳秒/国际热核实验堆(+

如果我在Rust中运行这些基准测试:

#[工作台]
fn工作台(b:和多台工作台){
设mut rng=rand::weak_rng();
b、 国际热核实验堆(| | rng.gen_范围::(2.0100.0));
}
#[法官席]
fn台架(b:和多台台架){
设mut rng=rand::weak_rng();
b、 国际热核实验堆(| | rng.gen_范围::(2.0100.0).ln());
}
结果是:

测试测试::测试台\u ln。。。试验台:121纳秒/国际热核实验堆(+/-2)
测试:台架试验。。。实验台:6纳秒/国际热核实验堆(+/-0)
121-6=115纳秒/次
ln
呼叫

但Java中的基准相同:

@State(Scope.Benchmark)
公共静态类Rnd{
final double x=ThreadLocalRandom.current().nextDouble(2100);
}
@基准
公共双测试日志(Rnd Rnd){
返回Math.log(rnd.x);
}
给我:

基准模式Cnt分数错误单位
Main.testLog avgt 20 31555±0234 ns/op
Rust中的日志速度约为Java中的3.7倍(115/31)

当我测试斜边实现(
hypot
)时,Rust中的实现速度是Java中的15.8倍

我是否编写了糟糕的基准测试,或者这是一个性能问题

对评论中提出的问题的答复:

  • “,”是我国的十进制分隔符

  • 我使用总是在发布模式下运行的
    货台
    运行Rust的基准测试

  • Java基准测试框架(JavaBenchmarkFramework,JMH)为每个调用创建一个新对象,即使它是
    静态
    类和
    最终
    变量。如果我在测试方法中添加一个随机创建,我得到43 ns/op

  • 答案是:

    解决了这个问题。之后,结果是:

    测试测试::测试台\u ln。。。实验台:43纳秒/国际热核实验堆(+/-3)
    测试:台架试验。。。实验台:5纳秒/国际热核实验堆(+/-0)
    

    我认为38(±3)足够接近31.555(±0.234)。

    我将提供另一半的解释,因为我不知道生锈
    Math.log
    @hostpotintrinsiccandidate
    注释,这意味着对于这样的操作,它将被本机CPU指令所取代:想想
    Integer.bitCount
    ,它将执行大量移位,或者使用速度更快的直接CPU指令

    有这样一个非常简单的程序:

    publicstaticvoidmain(字符串[]args){
    系统输出打印Ln(mathLn(20_000));
    }
    私有静态long-mathLn(int x){
    长结果=0L;
    对于(int i=0;i
    并使用以下工具运行它:

    java-XX:+UnlockDiagnosticVMOptions
    -XX:+printinline
    -XX:+PrintIntrinsics
    -XX:CICompilerCount=2
    -XX:+打印编译
    包/类名
    
    它将生成许多行,但其中之一是:

    @2 java.lang.Math::log(5字节)内在
    
    使这段代码非常快


    我真的不知道什么时候,如何发生在生锈,虽然

    用java作为基准不是很糟糕吗?我的意思是java很好,但在某些情况下,它太好了。你可能在测试随机数生成器,而不是日志函数。此外,我相信Rust只使用系统数学库,因此对
    log
    的纯调用应该与C中的调用相同(不知道Java)。您是否可以使用
    RUSTFLAGS='-Ctarget cpu=native'cargo bench
    ?@SimonByrne重新运行测试,这难道不会被只测试RNG的
    bench\u rnd
    功能所抵消吗?这就是OP减去两个Rust基准计时的原因——为
    ln
    函数创建一个纯粹的基准。我同意它应该只调用系统数学库。我对java一无所知,但你确定x是更新的吗?因为Rust是静态编译的(或者AOT,如果你愿意的话),所以它必须知道一个编译到的平台。默认情况下,它有点保守(例如,32位x86代码可能针对686处理器)。
    -Ctarget cpu=native
    标志告诉编译器以运行编译器的机器为目标;这允许编译器使用完整的可用指令集(如
    popcnt
    示例)。
    export RUSTFLAGS='-Ctarget-cpu=native'