Laz*_*535 6 performance exception divide-by-zero rust
为了更好地理解Rusts恐慌/异常机制,我编写了以下代码:
#![feature(libc)]
extern crate libc;
fn main() {
let mut x: i32;
unsafe {
x = libc::getchar();
}
let y = x - 65;
println!("{}", x);
let z = 1 / y;
println!("{}", z);
}
Run Code Online (Sandbox Code Playgroud)
我想检查Rust如何处理除零案例.最初我假设它要么面对未处理的SIGFPE并且正在死亡,要么实施了一个处理程序并将其重新路由到恐慌(现在可以处理?).
代码是冗长的,因为我想确保Rust在编译时知道某些东西是零,因此用户输入时不会做任何"智能".只要给它一个'A'就可以了.
我发现Rust实际上产生的代码每次在除法发生之前检查零除法.我甚至看了一次装配.:-)
长话短说:我可以禁用此行为吗?我想对于较大的数据集,这可能会产生很大的性能影响.为什么不使用我们的CPU能力为我们检测这些东西?我可以设置自己的信号处理程序并处理SIGFPE吗?
根据Github上的一个问题,前一段时间的情况肯定是不同的.
我认为事先检查每个部门远离"零成本".你怎么看?我错过了一些明显的东西吗
我认为事先检查每个部门远离"零成本".你怎么看?
你测量了什么?
执行的指令数量很少代表性能; 矢量化代码通常更冗长,但速度更快.
所以真正的问题是:这个分支的成本是多少?
由于故意除以0是不太可能的,并且偶然地做它只是稍微更可能,除非出现0除法,否则将始终正确地预测分支.但是,考虑到恐慌的代价,错误预测的分支是您最不担心的.
因此,成本是:
确切的影响难以取得资格,对于数学繁重的代码,它可能会产生影响.虽然我会提醒你一个整数除法是〜100个循环1开始,所以数学繁重的代码会尽可能地避开它(它可能是你CPU中最耗时的单指令).
1 请参阅Agner Fog的指令表:例如,在Intel Nehalem DIV上,64位积分上的IDIV的延迟分别为28到90个周期和37到100个周期.
除此之外,rustc在LLVM之上实现,它委托实际的代码生成.因此,在许多情况下,rustc受LLVM的支配,这就是其中之一.
LLVM有两个整数除法指令:udiv和sdiv.
两者都有未定义的行为,除数为0.
Rust旨在消除Undefined Behavior,因此必须防止0除以,以免优化器将发出的代码破坏而无法修复.
它使用LLVM手册中的建议进行检查.
小智 5
长话短说:我可以禁用此行为吗?
是的你可以:std::intrinsics::unchecked_div(a, b)。你的问题也适用于余数(这就是 Rust 调用modulo 的方式):std::intrinsics::unchecked_rem(a, b)。我在这里检查了汇编输出,将其与 C++ 进行比较。
在文档中它指出:
这是一个仅限夜间使用的实验性 API。(核心内部函数)
内在函数不太可能稳定,相反,它们应该通过标准库其余部分中的稳定接口来使用
因此,您必须使用夜间构建,并且由于Matthieu M.已经指出的原因,它不太可能以稳定的形式进入标准库。