为什么不使用CPUID而不捕获未定义指令异常?

时间:2020-04-26 11:13:02

标签: x86 cpuid hammingweight

假设我要使用一条可能不可用的指令。而且该指令不是那些透明的后备指令,当它不可用时它是未定义的指令。例如说popcnt

我可以代替使用cpuid来尝试打电话吗?

如果失败,我将捕获该异常,并将此信息保存在bool变量中,并将在以后继续使用其他分支。

当然会有性能损失,但是只有一次。这种方法还有其他缺点吗?

1 个答案:

答案 0 :(得分:1)

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

一旦您解决了这一问题,便找出了哪条指令出错并对其进行仿真并修改了保存的任务状态,问题就变成了一个包含popcnt的循环的性能,该循环在您乐观地分派到{{1 }}版本。

如果您的整个代码是用asm编写的(或者编译器可以为您编写此代码),则也许合理,但是信号处理程序很难收集所有必要的状态并在其他版本中恢复执行这样的循环。

(GNU / Linux信号处理程序对于正在运行的线程的已保存寄存器状态获得了非标准的支持,因此从理论上讲,您可以在那里执行此操作。)

大概这仅与提前编译有关;如果您正在使用JIT,则应该提前检查CPUID,而不要构建异常处理路径。


能够高效地分派意味着您的代码可能已经用多版本函数的函数指针编写了。

因此,这里唯一保存的是一个简单的init函数,您的程序只运行一次,它将运行CPUID两次并设置所有函数指针。除非需要大量使用函数指针,否则根据需要延迟执行此操作意味着更多的缓存丢失。例如popcnt

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


如果您的程序具有使用的多个CPU功能,您还需要知道哪个指令出错。

如果您要进行仿真或其他操作,则需要检查它是否是可能会引发large-program --help执行/ SIGILL信号的预期指令之一。例如通过检查故障地址上的机器代码。

但是,如果您改为让函数跟踪它们刚刚执行的乐观调度(以便他们可以检测到它是否起作用),则需要在每次调度之前设置一个变量,这样实际上会产生额外的开销。 / p>