我有一个代码,我在 Intel Xeon Phi Knights Landing (KNL) 7210(64 核)处理器(它是一台 PC,处于本机模式)上启动并使用 Intel c++ 编译器(icpc)版本 17.0.4。我还在英特尔酷睿 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;
}
...
Particle p[N];
- 一个粒子数组,Particle 是一个浮点结构。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
包含在-march=native
KNL 的标志中?我可以在 KNL 上启动代码时替换标志
-march=native
(-march=knl
在 i7 上一切正常),它们是否等效?如果使用英特尔编译器,为获得最佳性能而编写的标志集是最优的吗?
正如 Peter Cordes 所说,当程序在 GDB 中抛出浮点异常时,我将汇编器输出放在这里:1)(gdb)disas 的输出:
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 了。我从程序调试开始就使用它,因为我们在代码中有错误(浮点异常)并且必须更正它们。