добавление флага компилятора «-march = native» в строку компиляции приводит к исключению с плавающей запятой в KNL - PullRequest
0 голосов
/ 01 октября 2018

У меня есть код, который я запускаю на процессоре Intel Xeon Phi Knights Landing (KNL) 7210 (64 ядра) (это ПК в собственном режиме) и использую компилятор Intel c ++ (icpc) версии 17.0.4.Также я запускаю тот же код на процессоре Intel Core i7, где версия ICPC 17.0.1.Чтобы быть более правильным, я компилирую код на машине, которую я запускаю (скомпилирован на i7 и запущен на i7, то же самое для KNL).Я никогда не делаю двоичный файл на одной машине и не переносю его на другую.Циклы распараллелены и векторизованы с использованием OpenMP.Для лучшей производительности я использую флаги компилятора Intel:

-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, но они выдают ту же ошибку.

Итак, я хотел спросить:

  1. Почему -march=native,-xMIC-AVX512 не работают и -march=knl работают;-xMIC-AVX512 включено в -march=native флаг для KNL?

  2. Могу ли я заменить флаг -march=native на -march=knl при запуске кода на KNL (на i7 все работает)Являются ли они эквивалентными?

  3. Является ли набор флагов записанным оптимальным для достижения максимальной производительности при использовании компилятора Intel?

Как сказал Питер Кордес, я поместил здесь вывод ассемблера, когда программа выдает исключение с плавающей точкой в ​​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);
  ...
}

Я должен подчеркнуть, что я уже использовал feenable, за исключением случаев, когда я получил эту ошибку .Я использовал его с начала отладки программы, потому что у нас были ошибки (исключения с плавающей запятой) в коде, и мы должны были их исправить.

1 Ответ

0 голосов
/ 02 октября 2018

Вы использовали feenableexcept для снятия маскировки с некоторых исключений FP, поэтому оптимизации, создающие недопустимые временные результаты, приведут к сбою вашей программы.

Компилятор Intel с -fp-model fast=2, такой как gcc -ffast-math, предполагает, что исключения FPзамаскирован так, что он может вызывать FE_INVALID в некоторых элементах SIMD при некоторых временных вычислениях, если все в итоге работает (например, смешивание для исправления элементов, где-то неверный rece-sqrt).Я бы предположил, что это происходит здесь.

Если вы публикуете разборку действительной инструкции, которая вызвала ошибку (вместо набора целочисленных умножений в самом начале этой функции), мы можем точно определить, какая оптимизациявызвало недопустимый временный характер, но в целом вам нужно использовать менее агрессивные параметры FP при компиляции сборок, которые включают исключения FP.


Согласно документации Intel :

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

Семантика исключений с плавающей точкой отключена по умолчанию и не может быть включена, потому что вы не можете указать быстрый и только вместе в одной компиляции .Чтобы включить семантику исключений, вы должны явно указать другое ключевое слово (подробности см. В описании других ключевых слов).

Вам нужно использовать -fp-model except, если вы хотите, чтобы компилятор учитывал тот факт, что FPИсключением является видимый побочный эффект. Это не по умолчанию.

Если вы собираетесь вызывать функции, которые изменяют среду FP,ISO C говорит, что вы должны использовать #pragma STDC FENV_ACCESS ON, и что без этого модификации среды FP не будут "значимыми".«В противном случае реализация может предположить, что режимы управления с плавающей точкой всегда являются режимами по умолчанию и что флаги состояния с плавающей точкой никогда не проверяются и не изменяются».Я не уверен, что включение исключений действительно имеет значение.Возможно, это не важно, если вы делаете это один раз при запуске программы, иначе будет иметь значение, будет ли вычисление выполнено до или после включения исключений.


Аналогично для gcc, -ffast-math включает-fno-trapping-math, который обещает компилятору, что инструкции FP не будут вызывать SIGFPE, просто незаметно устанавливает биты закрепления состояния в MXCSR и выдает NaN (недопустимый), + -Infinity (переполнение) или 0.0 (недополнение).

...