对于某些例程,如果使用BMI2指令,我可以获得明显更好的性能,而不是坚持使用“标准”x86-64指令集.麻烦的是,BMI2最近刚推出,我的一些用户使用不支持这些指令的处理器.
所以,我写过两次优化程序,一次使用BMI2指令,一次不使用它们.在我目前的设置中,我将分发两个版本的.a文件:一个需要支持BMI2指令的“快速”版本,以及一个不需要支持BMI2指令的“慢”版本.
我问是否有办法通过分发单个.a文件来简化这一过程,该文件将根据最终应用程序运行的cpu是否支持BMI2指令动态选择正确的实现.
与StackOverflow上的类似问题不同,这里有两个特点:
>选择函数的技术需要在关键路径中具有特别低的开销.在汇编优化之后,所讨论的例程在大约10 ns内运行,因此即使单个if语句也可能很重要.
>需要“动态”选择的功能在开始时选择一次,然后在程序的持续时间内保持固定.我希望这将提供比这个问题中建议的更快的解决方案:Choosing method implementation at runtime
我到目前为止提出的最快解决方案是执行以下操作:
>使用cpuid指令检查cpu是否支持BMI2指令.
>根据结果设置全局变量true或false.
>在每个函数调用上对此全局变量的值进行分支.
我对这种方法不满意,因为它有两个缺点:
>我不确定如何自动运行cpuid并在程序开头设置一个全局变量,因为我正在分发一个.a文件并且无法控制最终二进制文件中的main函数.如果它提供了更好的解决方案,我很高兴在这里使用C,只要最终的库仍然可以与C程序链接和调用.
>这会在每个函数调用上产生开销,理想情况下,唯一的开销是在程序启动时.
有没有比我上面详述的更有效的解决方案?
解决方法
如果你的功能依赖于pdep / pext,你可能想要检测AMD与英特尔,因为AMD的pdep / pext非常慢并且可能不值得在Ryzen上使用,即使它可用. (有关说明表,请参阅https://agner.org/optimize/.)
函数指针的开销相当低,与调用共享库或DLL中的函数大致相同.调用[rel funcptr]而不是调用func. (在编译器生成的asm中调用您的函数).
CPU dependent code: how to avoid function pointers?在C中显示了一个非常简单的例子,并且正在寻找避免它的方法.通过动态链接,您可以在动态链接时进行cpu检测,因此动态链接间接也成为您的cpu调度间接(就像glibc选择优化的memcpy实现一样).
但是对于.a的静态链接,只需要将基本版本静态初始化的函数指针,以及你的cpu初始化函数(希望在任何函数指针被解除引用之前运行)重写它们以指向最佳版本.当前的cpu.