gpt4 book ai didi

c++ - 将 "-march=native"intel 编译器标志添加到编译行会导致 KNL 上出现浮点异常

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:04:45 26 4
gpt4 key购买 nike

我有一个代码,我在 Intel Xeon Phi Knights Landing (KNL) 7210(64 核)处理器(它是一台 PC, native 模式)上启动并使用 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 是一个 float 结构。 N - 最大粒子数。

如果要删除标志 -march=native 或将其替换为 -march=knl-march=core-avx2,一切正常。这个标志对程序做了坏事,但是什么 - 我不知道。

我在互联网(https://software.intel.com/en-us/articles/porting-applications-from-knights-corner-to-knights-landinghttps://math-linux.com/linux/tip-of-the-day/article/intel-compilation-for-mic-architecture-knl-knights-landing)中发现应该使用标志:-xMIC-AVX512。我尝试使用此标志和 -axMIC-AVX512,但它们给出了相同的错误。

所以,我想问的是:

  1. 为什么 -march=native-xMIC-AVX512 不起作用而 -march=knl 起作用; -xMIC-AVX512 是否包含在 KNL 的 -march=native 标志中?

  2. 当我在 KNL 上启动代码时(在 i7 上一切正常),我可以将标志 -march=native 替换为 -march=knl 吗?等效?

  3. 如果使用 Intel 编译器,为获得最佳性能而编写的标志集是否最优?

正如 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。我从程序调试开始就使用它,因为我们在代码中有错误(浮点异常)并且必须更正它们。

最佳答案

您使用 feenableexcept 来揭露一些 FP 异常,因此创建无效临时结果的优化将使您的程序崩溃。

带有 -fp-model fast=2 的英特尔编译器,如 gcc -ffast-math,假定 FP 异常被屏蔽,因此它可能导致 FE_INVALID 在某些临时计算中的某些 SIMD 元素中,只要最终一切正常(例如,混合以修复 recip-sqrt 出错的元素)。我假设这就是这里发生的事情。

如果您对发生故障的实际指令进行反汇编(而不是在该函数的最开始进行一堆整数乘法),我们可以准确地找出是什么优化导致了什么无效临时,但通常您需要使用更少编译打开 FP 异常的构建时,激进的 FP 选项。


根据 Intel's documentation :

-fp-model fast[=1|2] or /fp:fast[=1|2]

Floating-point exception semantics are disabled by default and they cannot be enabled because you cannot specify fast and except together in the same compilation. To enable exception semantics, you must explicitly specify another keyword (see other keyword descriptions for details).

如果您希望编译器尊重 FP 异常是可见副作用这一事实,则需要使用 -fp-model except。 strong>默认情况下开启。

如果你要调用修改 FP 环境的函数,ISO C 说你应该使用 #pragma STDC FENV_ACCESS ON ,如果没有它,对 FP 环境的修改就不是“有意义的”。 “否则,实现可以自由地假设浮点控制模式始终是默认模式,并且永远不会测试或修改浮点状态标志。”我不确定启用异常是否真的很重要。可能并不重要,只要您在程序启动时执行一次,否则计算是在启用异常之前还是之后发生就很重要了。


与 gcc 类似,-ffast-math 包括 -fno-trapping-math,它向编译器 promise FP 指令不会引发 SIGFPE,只是默默地设置粘性MXCSR 中的状态位并产生 NaN(无效)、+-Infinity(溢出)或 0.0(下溢)。

关于c++ - 将 "-march=native"intel 编译器标志添加到编译行会导致 KNL 上出现浮点异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52592058/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com