我有一份代码,我在拥有64个核心的Intel Xeon Phi Knights Landing(KNL)7210处理器上运行它(它是原生模式下的PC),并使用Intel c ++编译器(icpc)版本17.0.4。同时,我在Intel Core i7处理器上运行相同的代码,其中icpc的版本为17.0.1。更准确地说,我在启动代码的机器上编译它(在i7上编译并在i7上启动,在KNL上也是如此)。循环使用OpenMP进行并行化和矢量化。为了获得最佳性能,我使用英特尔编译器标志:
-DCMAKE_CXX_COMPILER="-march=native -mtune=native -ipo16 -fp-model fast=2 -O3 -qopt-report=5 -mcmodel=large"
在i7上一切运作正常。但是在KNL上,如果不加-march=native
选项,代码可以正常工作,如果添加该选项,程序会立即抛出浮点异常。如果仅使用"-march=native"标志进行编译,则情况相同。如果使用gdb调试,则它指向代码片段中的pp+=alpha/rd
行。
...
the code above is run in 1 thread
double K1=0.0, P=0.0;
#pragma omp parallel for reduction(+:P_x,P_y,P_z, K1,P)
for(int i=0; i<N; ++i)
{
P_x+=p[i].vx*p[i].m;
P_y+=p[i].vy*p[i].m;
P_z+=p[i].vz*p[i].m;
K1+=p[i].vx*p[i].vx+p[i].vy*p[i].vy+p[i].vz*p[i].vz;
float pp=0.0;
#pragma simd reduction(+:pp)
for(int j=0; j<N; ++j) if(i!=j)
{
float rd=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)+(p[i].z-p[j].z)*(p[i].z-p[j].z));
pp+=alpha/rd;
}
P+=pp;
}
...
粒子p[N];
- 一个由浮点数构成的结构体数组。N为粒子数量上限。
如果删除标志-march=native
或将其替换为-march=knl
或-march=core-avx2
,则一切正常。这个标志对程序有负面影响,但我不知道是什么。
我在互联网上找到了 (https://software.intel.com/en-us/articles/porting-applications-from-knights-corner-to-knights-landing, https://math-linux.com/linux/tip-of-the-day/article/intel-compilation-for-mic-architecture-knl-knights-landing),其中提到应使用以下标志:-xMIC-AVX512
。我尝试使用此标志和-axMIC-AVX512
,但它们产生相同的错误。
所以,我想问的是:
为什么
-march=native
,-xMIC-AVX512
不能工作,而-march=knl
可以工作;-xMIC-AVX512
是否包含在KNL的-march=native
标志中?当我在KNL上运行代码时,是否可以用
-march=knl
替换标志-march=native
(在i7上一切正常)?它们是等效的吗?如果使用英特尔编译器,所写的标志集是否最优以获得最佳性能?
正如Peter Cordes所说,当程序在GDB中抛出浮点异常时,我在这里放置了汇编输出:
Program received signal SIGFPE, Arithmetic exception.
0x000000000040e3cc in randomizeBodies() ()
Missing separate debuginfos, use: debuginfo-install libgcc-4.8.5-
16.el7.x86_64 libstdc++-4.8.5-16.el7.x86_64
(gdb) disas
Dump of assembler code for function _Z15randomizeBodiesv:
0x000000000040da70 <+0>: push %rbp
0x000000000040da71 <+1>: mov %rsp,%rbp
0x000000000040da74 <+4>: and $0xffffffffffffffc0,%rsp
0x000000000040da78 <+8>: sub $0x100,%rsp
0x000000000040da7f <+15>: vpxor %xmm0,%xmm0,%xmm0
0x000000000040da83 <+19>: vmovups %xmm0,(%rsp)
0x000000000040da88 <+24>: vxorpd %xmm5,%xmm5,%xmm5
0x000000000040da8c <+28>: vmovq %xmm0,0x10(%rsp)
0x000000000040da92 <+34>: mov $0x77359400,%ecx
0x000000000040da97 <+39>: xor %eax,%eax
0x000000000040da99 <+41>: movabs $0x5deece66d,%rdx
0x000000000040daa3 <+51>: mov %ecx,%ecx
0x000000000040daa5 <+53>: imul %rdx,%rcx
0x000000000040daa9 <+57>: add $0xb,%rcx
0x000000000040daad <+61>: mov %ecx,0x9a3b00(,%rax,8)
0x000000000040dab4 <+68>: mov %ecx,%esi
0x000000000040dab6 <+70>: imul %rdx,%rsi
0x000000000040daba <+74>: add $0xb,%rsi
0x000000000040dabe <+78>: mov %esi,0x9e3d00(,%rax,8)
0x000000000040dac5 <+85>: mov %esi,%edi
0x000000000040dac7 <+87>: imul %rdx,%rdi
0x000000000040dacb <+91>: add $0xb,%rdi
0x000000000040dacf <+95>: mov %edi,0xa23f00(,%rax,8)
0x000000000040dad6 <+102>: mov %edi,%r8d
0x000000000040dad9 <+105>: imul %rdx,%r8
0x000000000040dadd <+109>: add $0xb,%r8
0x000000000040dae1 <+113>: mov %r8d,0xa64100(,%rax,8)
0x000000000040dae9 <+121>: mov %r8d,%r9d
0x000000000040daec <+124>: imul %rdx,%r9
0x000000000040daf0 <+128>: add $0xb,%r9
0x000000000040daf4 <+132>: mov %r9d,0xaa4300(,%rax,8)
0x000000000040dafc <+140>: mov %r9d,%r10d
0x000000000040daff <+143>: imul %rdx,%r10
0x000000000040db03 <+147>: add $0xb,%r10
0x000000000040db07 <+151>: mov %r10d,0x9a3b04(,%rax,8)
0x000000000040db0f <+159>: mov %r10d,%r11d
0x000000000040db12 <+162>: imul %rdx,%r11
0x000000000040db16 <+166>: add $0xb,%r11
0x000000000040db1a <+170>: mov %r11d,0x9e3d04(,%rax,8)
0x000000000040db22 <+178>: mov %r11d,%ecx
0x000000000040db25 <+181>: imul %rdx,%rcx
0x000000000040db29 <+185>: add $0xb,%rcx
0x000000000040db2d <+189>: mov %ecx,0xa23f04(,%rax,8)
2) p $mxcsr 的输出:
(gdb) p $mxcsr
1 = [ ZE PE DAZ DM PM FZ ]
3) p $ymm0.v8_float 的输出:
$2 = {3, 3, 3, 3, 3, 3, 3, 3}
4) p $zmm0.v16_float 的输出:
gdb) p $zmm0.v16_float
$3 = {3 <repeats 16 times>}.
我还应该提到,为了检测浮点异常,我使用了标准的
void handler(int sig)
{
printf("Floating Point Exception\n");
exit(0);
}
...
int main(int argc, char **argv)
{
feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
signal(SIGFPE, handler);
...
}
我需要强调的是,当我遇到这个错误时,我已经在使用feenableexcept。自从开始程序调试以来,我就一直在使用它,因为我们的代码中存在错误(浮点异常),必须加以纠正。
-march=native
与使用-march=skylake
或其他类似的编译效果相同。Native意味着生成的代码假定它正在运行的机器与编译它的机器相同,因此您不应该期望它能在其他机器上运行。 - Peter Cordesrd == 0.0
还是什么?你的KNL系统上是否有FP异常未屏蔽?不同的编译器选项可能会产生不同的FP行为(Intel的编译器启用了等效于-ffast-math
,因此它可能使用AVX512ER(仅限KNL)VRSQRT28PS来获得高精度快速逆平方根近似值,比普通AVX512的vrsqrt14ps
或普通SSE/AVX1的12位vrsqrtps
要好得多)。 - Peter Cordes