如果我在Rust中运行这些基准测试:
#[bench]
fn bench_rnd(b: &mut Bencher) {
let mut rng = rand::weak_rng();
b.iter(|| rng.gen_range::<f64>(2.0, 100.0));
}
#[bench]
fn bench_ln(b: &mut Bencher) {
let mut rng = rand::weak_rng();
b.iter(|| rng.gen_range::<f64>(2.0, 100.0).ln());
}
结果是:
test tests::bench_ln ... bench: 121 ns/iter (+/- 2)
test tests::bench_rnd ... bench: 6 ns/iter (+/- 0)
121-6 =每个ln
调用115 ns。
但Java中的基准测试是相同的:
@State(Scope.Benchmark)
public static class Rnd {
final double x = ThreadLocalRandom.current().nextDouble(2, 100);
}
@Benchmark
public double testLog(Rnd rnd) {
return Math.log(rnd.x);
}
给了我:
Benchmark Mode Cnt Score Error Units
Main.testLog avgt 20 31,555 ± 0,234 ns/op
Rust的日志速度比Java慢大约3.7倍(115/31)。
当我测试斜边实现(hypot
)时,Rust中的实现比Java快15.8倍。
我是否写了糟糕的基准测试,或者是性能问题?
对评论中的问题的回应:
cargo bench
运行Rust的基准测试,它总是在发布模式下运行。static
类和一个final
变量。如果我在测试的方法中添加一个随机创建,我会得到43 ns/op。发布于 2017-07-12 20:58:57
export RUSTFLAGS='-Ctarget-cpu=native'
修复了问题。在此之后,结果是:
test tests::bench_ln ... bench: 43 ns/iter (+/- 3)
test tests::bench_rnd ... bench: 5 ns/iter (+/- 0)
我认为38 (±3)已经足够接近31.555 (±0.234)了。
发布于 2017-07-12 22:08:19
我将提供另一半的解释,因为我不了解Rust。Math.log
被注释为@HotSpotIntrinsicCandidate
,这意味着对于这样的操作,它将被本机CPU指令取代:想想Integer.bitCount
,它要么进行大量的移位,要么使用直接的CPU指令,这样做的速度要快得多。
有一个非常简单的程序,像这样:
public static void main(String[] args) {
System.out.println(mathLn(20_000));
}
private static long mathLn(int x) {
long result = 0L;
for (int i = 0; i < x; ++i) {
result = result + ln(i);
}
return result;
}
private static final long ln(int x) {
return (long) Math.log(x);
}
并使用以下命令运行它:
java -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining
-XX:+PrintIntrinsics
-XX:CICompilerCount=2
-XX:+PrintCompilation
package/Classname
它将生成许多行,但其中一行是:
@ 2 java.lang.Math::log (5 bytes) intrinsic
让这段代码变得非常快。
我真的不知道这是什么时候以及如何在Rust中发生的。
https://stackoverflow.com/questions/45037547
复制相似问题