我正在使用一个C库,该库编译/链接到.a
文件,用户可以将其静态链接到其代码中。库的性能非常重要,因此我正在x86-64程序集中编写对性能至关重要的例程,以优化性能。
对于某些例程,如果我使用BMI2指令,则比使用“标准” x86-64指令集要好得多。麻烦的是,BMI2是最近才推出的,我的一些用户使用的处理器不支持这些指令。
因此,我编写了优化例程两次,一次使用BMI2指令,一次不使用它们。在我当前的设置中,我将分发.a
文件的两个版本:一个“快速”版本,它需要支持BMI2指令,一个“缓慢”版本,它不需要支持BMI2指令。
我在问是否有一种方法可以通过分发单个.a
文件来简化此操作,该文件将根据最终应用程序运行的CPU 是否支持BMI2动态选择正确的实现。说明。
与StackOverflow上的类似问题不同,这里有两个特点:
if
语句也可能很重要。到目前为止,我想出的最快的解决方案是执行以下操作:
cpuid
指令检查CPU是否支持BMI2指令。true
或false
。我对这种方法不满意,因为它有两个缺点:
cpuid
文件,因此我不确定如何自动运行.a
并在程序开始时设置全局变量并且无法控制最终二进制文件中的main
函数。 只要能仍与C程序链接和从其调用最终库,我很乐意在这里使用C ++,因为它提供了更好的解决方案。 有没有比我上面详细介绍的解决方案更有效的解决方案?
答案 0 :(得分:3)
x264使用init函数(在调用任何其他命令或类似操作之前,必须先调用库的用户)来基于CPUID结果设置函数指针的结构。包括考虑到pshufb
在某些支持它的早期CPU上运行缓慢。
如果您的功能依赖于pdep
/ pext
,则您可能想检测AMD与Intel,因为AMD的pdep
/ pext
非常慢,可能不值得即使在Ryzen上也可以使用。 (有关说明表,请参见https://agner.org/optimize/。)
函数指针的开销很低,大约与在共享库或DLL中调用函数相同。 call [rel funcptr]
,而不是call func
。 (在由编译器生成的调用您函数的asm中。)
CPU dependent code: how to avoid function pointers?在C中显示了一个非常简单的示例,并正在寻求避免的方法。借助动态链接,您可以在动态链接时进行CPU检测,因此动态链接间接也将成为您的CPU派发间接(就像glibc一样,用于选择优化的memcpy
实现)。
但是使用.a
的静态链接,只需将函数指针静态初始化为基准版本,然后您的CPU初始化函数(希望在取消引用任何函数指针之前运行)将它们重写为指向为当前CPU的最佳版本。
答案 1 :(得分:1)
如果使用的是gcc,则可以让编译器自动实现所有样板代码。 gcc manual page on function multiversioning