为什么我不应该捕获未定义的指令异常而不是使用 CPUID?



假设我想要使用一条可能不可用的指令。这个指令不是那些透明的回退,当它不可用时,它是未定义的指令。比如说它是popcnt

我可以不使用cpuid而是试着调用它吗?

如果失败,我将捕获异常,并将此信息保存在bool变量中,然后再使用另一个分支。

当然会有表演惩罚,但只有一次。这种方法还有其他缺点吗?

一个主要的困难是为第一个调用提供正确的执行。

一旦您通过找出出现故障的指令并对其进行仿真并修改保存的任务状态来解决此问题,问题就变成了包含popcnt的循环的性能,该循环在您乐观地调度到该循环的popcnt版本后运行了100万次迭代。

如果你的整个代码都是用asm编写的(或者编译器可以为你制作这段代码(,那么可能是合理的,但信号处理程序很难收集所有必要的状态并在其他版本的循环中恢复执行。

(GNU/Linux信号处理程序对它们运行的线程的保存寄存器状态进行了非标准处理,所以理论上你可以在那里完成这项工作。(

据推测,这只与提前编译有关;如果您是JITing,您应该提前检查CPUID,而不是构建异常处理路径。


能够高效调度意味着您的代码可能已经使用多版本函数的函数指针编写。

因此,这里唯一保存的是程序运行一次的一个简单init函数,它运行几次CPUID并设置所有函数指针。如果不使用大量的函数指针,稍后根据需要延迟执行意味着会有更多的缓存未命中。例如CCD_ 6。

这些异常/信号处理程序的代码可能不会比简单的init函数小。有趣的想法,但总的来说,我看不出任何有意义的全部好处。


如果程序使用多个CPU功能,您还需要知道哪个指令出现故障。

如果您正在模拟或其他什么,您需要检查它,看看它是否是可能引发#UD执行选项/SIGILL信号的预期指令之一。例如通过检查故障地址处的机器代码。

但是,如果你让函数跟踪他们刚刚进行的乐观调度(这样他们就可以检测它是否不起作用(,你需要在每次调度之前设置一个变量,这样实际上会增加额外的开销。

最新更新