我已经看到关于如何使用FMA指令集的问题,但在我开始使用它们之前,我首先想知道我是否可以(我的处理器是否支持它们)。我发现一个帖子说我需要看看(在Linux上工作)的输出:
more /proc/cpuinfo
找出答案。我得到这个:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 30
model name : Intel(R) Xeon(R) CPU X3470 @ 2.93GHz
stepping : 5
cpu MHz : 2933.235
size : 8192 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 4
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 11
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni
dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm ida dts tpr_shadow vnmi flexpriority ept vpid
bogomips : 5866.47
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
似乎最有趣的是标志部分,但我不确定如何从该列表中找出处理器是否支持这些指令。
有谁知道怎么知道吗?谢谢你。
我假设您希望在编译时在C/c++中检测它。
FP_FAST_FMA
宏不是检测FMA指令集的可靠方法。如果std::fma
比x*y+z
快,则在"math.h"
/<cmath>
中定义该宏,如果它是基于FMA指令集的内在函数,则可能是这样。否则,它将使用非内在函数,这是非常缓慢的。现在在2016年GCC的默认glibc/libstdc++定义了这个宏,但大多数其他标准库实现没有(包括LLVM libc++, ICC和MSVC)。这并不意味着他们没有实现std::fma
作为一个内在的,如果可能的话,他们只是忘记定义这个宏。
可靠的FMA检测
要在编译时可靠地检测FMA(或任何指令集),您需要使用特定于指令集的宏。这些宏是由编译器根据选择的目标体系结构和/或指令集定义的。
有一个__FMA__
宏用于FMA/FMA3支持,__FMA4__
宏用于AMD FMA4支持。GCC、clang和ICC都定义了它们。
遗憾的是,除了__AVX__
和__AVX2__
之外,MSVC没有定义任何指令集特定的宏。
交叉编译FMA检测
对于Intel处理器,FMA是由Intel Haswell与AVX2一起引入的。
对于AMD处理器来说,事情有点混乱。FMA4是由AMD推土机引入AVX和XOP的。FMA3 (Intel FMA等效)是由AMD Piledriver推出的。通过FMA (__FMA__
宏)和BMI (__BMI__
宏)指令集,您可以在编译时将Piledriver与其前身Bulldozer区分开来。不幸的是,MSVC没有定义这两个
然而,与Intel处理器一样,如果AVX2存在,所有AMD处理器都支持FMA/FMA3
如果你想要交叉编译器检测目标架构是否支持FMA/FMA3,你必须检测__AVX2__
宏,因为如果AVX2是启用的,它是由所有主要编译器(包括MSVC)定义的:
#if !defined(__FMA__) && defined(__AVX2__)
#define __FMA__ 1
#endif
不幸的是,没有可靠的方法来检测AMD FMA4仅使用__AVX__
和__AVX2__
宏。
FMA指令实际上只有在编译器启用的情况下才能在程序中使用。在GCC和clang中,您需要设置适当的目标体系结构(如-march=haswell
)或手动启用带有-mfma
标志的FMA指令集。ICC以-xavx2
标志自动启用FMA。MSVC启用FMA与/arch:AVX2 /fp:fast /O2
选项。
AMD宣布未来将放弃对FMA4的支持
是的,如果你有,它会出现在flags
部分下面。在Intel Haswell机器上,我得到
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm
而在AMD的打桩机上,我得到
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc extd_apicid aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 popcnt aes xsave avx f16c lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid_msr tbm topoext perfctr_core perfctr_nb arat cpb hw_pstate npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold bmi1
(注意它包括一个fma4
标志,以及标准的fma
标志)。
所以在Linux上检查的一个简单方法是看返回代码:
grep fma < /proc/cpuinfo
OS X没有/proc/cpuinfo
,但是你可以这样做:
sysctl -n hw.optional.fma
将打印0(没有fma)或1(有fma)。
如果你使用的是C/c++,你也可以使用FP_FAST_FMA
宏