动态链接器中的运行时cpu检测(ld.so)

osg*_*sgx 5 c linux optimization linker

我想将运行时CPU Dispatch集成到我的库中.我有几个版本的功能,针对sse2/sse3/avx和x87通用变体进行了优化.我想将所有版本编译成单个.so库,我想如何实现一个cpu调度程序.

我认为最快的方法是在链接步骤(动态链接)获取cpu调度,所以当ld.so将加载我的库时,我希望它检查,cpu是否支持sse2,sse3或avx,然后我想要ld .so选择正确的功能集.

例如(使用gcc目标属性):

图书馆:

float* func3_generic(float *a, float *b)  __attribute__ ((__target__ ("fpmath=387")));
float* func3_sse2(float *a, float *b)  __attribute__ ((__target__ ("sse2")));
float* func3_sse3(float *a, float *b)  __attribute__ ((__target__ ("sse3")));
float* func3_avx(float *a, float *b)  __attribute__ ((__target__ ("avx")));
Run Code Online (Sandbox Code Playgroud)

我想有一些特殊的符号func3(),这将通过连接器(ld.so)被设置好的,以最先进的func3_generic,func3_sse2,func3_sse3,func3_avx.所以,如果cpu是Core i7-xxxx,我希望每次调用func3都会调用func3_avx,如果cpu是PentiumPro,调用func3将调用func3_generic.

同时我不想手动编写大量的调度代码,我希望以最小的开销选择正确的变量(没有额外的间接跳转).这意味着我可以在应用程序启动时花费额外的时间,但在调用此函数时没有任何额外的时间(在某些情况下会有非常多的调用).

UPDATE.链接器可以根据AUXV向量,AT_HWCAP:字段进行调度:

$ LD_SHOW_AUXV=1 /bin/echo
...
AT_HWCAP:    fpu ... mmx fxsr sse sse2
Run Code Online (Sandbox Code Playgroud)

Jam*_*mes -1

如何使用函数指针数组,然后使用 CPUID 指令让它们在启动时指向特定的实现。启动时所需的周期数应该很小。

如果您确实想避免任何启动成本,另一种方法是编写另一个小程序来查询 CPU 的功能,然后为 gcc 构造一个命令行,并定义一些宏,以便仅编译某些函数实现。

CPUID指令

  • 我相信 @James 的意思是使 `func3()` 类似于 `static (float* fnPtr)(float*,float*) = NULL; if (NULL == fnPtr) fnPtr = set_up_pointer(); return *fnPtr(a,b);` …但这将是您提到的额外间接跳转? (2认同)