Performance 我是否可以在每次除法时禁用零除法检查?

Performance 我是否可以在每次除法时禁用零除法检查?,performance,exception,rust,divide-by-zero,Performance,Exception,Rust,Divide By Zero,为了更好地理解锈菌恐慌/异常机制,我编写了以下代码: #![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); } 我想看看Rust是如何处理零除法

为了更好地理解锈菌恐慌/异常机制,我编写了以下代码:

#![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);
}
我想看看Rust是如何处理零除法的。最初我认为它要么是把一个未处理的SIGFPE带到脸上然后死去,要么是它实现了一个处理程序并将其重新路由到一个恐慌状态(现在可以处理吗?)

代码是冗长的,因为我想确保Rust在编译时知道某些内容为零时不会做任何“聪明”的事情,因此用户输入为零。只要给它一个“A”,它就会成功

我发现Rust实际上生成的代码每次除法之前都会检查零除法。我甚至看了一次大会。:-)


长话短说:我可以禁用此行为吗?我认为对于较大的数据集,这可能会对性能产生相当大的影响。为什么不使用我们的CPU能力来检测这些东西呢?我可以设置自己的信号处理器并处理SIGFPE吗

根据情况,前一段时间肯定有所不同

我认为事先检查每个部门远离“零成本”。你怎么认为?我错过了什么明显的东西吗

我认为事先检查每个部门远离“零成本”。你觉得怎么样

你量了多少

执行的指令数量是性能的一个很差的代表;矢量化代码通常更详细,但速度更快

所以真正的问题是:这个分支的成本是多少

由于故意除以0是不太可能的,而意外地这样做的可能性仅稍高一点,因此除非发生除以0的情况,否则分支总是能够正确预测的。但是,考虑到恐慌的代价,预测失误的分支是你最不担心的

因此,成本为:

  • 稍微胖一点的组件
  • 分支预测器中已占用的插槽
确切的影响很难确定,对于数学密集型代码来说,它可能会产生影响。尽管我要提醒您,整数除法的开始是~100个循环,因此数学密集型代码将尽可能避开它(它可能是CPU中最耗时的一条指令)

1请参阅:例如,在64位积分上的Intel Nehalem DIV和IDIV上,延迟分别为28到90个周期和37到100个周期


除此之外,rustc是在LLVM之上实现的,它将实际的代码生成委托给LLVM。因此,在许多情况下,RUSC都受LLVM的支配,这就是其中之一

LLVM有两条整数除法指令:

两者都具有除数为0的未定义行为

Rust旨在消除未定义的行为,因此必须防止发生被0除的情况,以免优化器将发出的代码弄得无法修复

它使用LLVM手册中建议的检查

长话短说:我可以禁用此行为吗

是的,你可以。 你的问题也适用于余数(Rust就是这样称呼的):。 我检查了程序集输出,将它与C++ ++。 它在文件中指出:

这是一个每晚只做实验的API。(核心要素)

本质不太可能稳定,相反,它们应该通过标准库其余部分中的稳定接口使用


因此,您必须使用夜间构建,并且它不太可能以稳定的形式出现在标准库中,原因已经指出。

我感到困惑。您想使用检查除法还是禁用除数为零的检查?“为什么不使用我们的CPU功能来检测这些内容?”并非所有CPU都具有这种功能。x86在除法为零时引发了一个异常,但其他人没有;e、 g.ARM静默返回一个0的结果。整数除法是~100个循环。我用C/C++和类似的场景做了一些测试,但都没有检查任何东西。还使用Clang(++)编译。不知为什么,Clang不尊重LVVM的这个建议,因为它们是如何“接近”的。“LaZARUS 535:AH,但是在C和C++中,整数除法具有不确定的行为(按规格),因此它是“正常的”。让Clang调用
udiv
sdiv
,而无需事先检查。@C标准明确允许Lazarus535 Clang在除以零时产生未定义的行为。另一方面,Rust避免了安全代码中未定义的行为。如果Rust在整数类型上提供了一个
不安全的fn divide\u unchecked(divisor:T)
方法,它将保持其承诺,但它不存在,可能是因为答案中解释的原因。此成本分析缺少最大的成本:此检查使您的函数更大,因此它们不太可能内联,这可能是任意昂贵的,因为其他丢失的优化会带来机会成本。分支预测表中的条目数量也是有限的,如果系统地将程序中的每一个分区都生成这个额外的代码,那么很可能会产生显著的影响。Rust已经使用SIGSEGV处理程序进行零成本堆栈溢出检测,为什么不使用SIGFPE进行零成本除以零检测呢?感谢您提供了这个非常有趣的答案!这是一个艰难的决定,但我现在接受了。有反对意见吗?@Lazarus535我想你问了两个问题:“长话短说:我可以禁用这种行为吗?”和“我认为事先检查每个部门远离“零成本”。你怎么看?我是否遗漏了一些明显的东西?”。我回答了第一个问题,Matthieu M.回答了第二个问题。不过我没有反对:)。