gfortran 또는 ifort 컴파일러는 두 배열의 곱을 합산할 때 SIMD 명령어를 현명하게 사용합니까?
-
22-12-2019 - |
문제
numpy로 작성된 코드가 있는데 더 나은 성능을 위해 Fortran으로 이식하는 것을 고려하고 있습니다.
제가 여러 번 수행하는 작업 중 하나는 두 배열의 요소별 곱을 합하는 것입니다.
sum(A*B)
융합된 곱셈-덧셈 명령어가 도움이 될 것 같습니다.현재 프로세서가 이러한 지침을 지원하지 않으므로 아직 테스트할 수 없습니다.그러나 FMA3(Intel Haswell 프로세서)를 지원하는 새 프로세서로 업그레이드할 수 있습니다.
"-march=native"(또는 ifort와 동등한 것)를 사용하여 프로그램을 컴파일하는 것이 컴파일러(gfortran 또는 ifort)가 SIMD 명령을 현명하게 사용하여 해당 코드를 최적화하도록 하는 데 충분한지 아는 사람이 있습니까? 아니면 제가 그렇게 생각합니까? 컴파일러나 코드를 잘 다루어야 합니까?
해결책 3
Xiaolei Zhu 팁 덕분에 Gfortran은 sum(A*B)
를 최적화하기 위해 융합 된 곱하기 추가를 사용한다는 것을 알고 있습니다. 예를 들어,이 코드로 :
프로그램 테스트 암시 적 없음
실제, 치수 (7) :: A, B
a= (/ 2.0, 3.0, 5.0, 7.0, 11.0, 13.0, 17.0 /)
b= (/ 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0 /)
인쇄 *, 합 (A * B)
ENDPROGRAM
i f95 sum.f95 -o sum -O3 -march=core-avx2
로 컴파일 할 수 있으며 objdump -d sum | grep vfmadd
디스플레이
40088B : C4 E2 71 99 44 24 30 VFMADD132SS 0x30 (% rsp), % xmm1, % xmm0
400892 : C4 E2 69 B9 44 24 VFMADD231SS 0x34 (% rsp), % xmm2, % xmm0
400899 : C4 E2 61 B9 44 24 38 VFMADD231SS 0x38 (% rsp), % xmm3, % xmm0
4008A0 : C4 E2 59 B9 44 24 3C VFMADD231SS 0x3C (% RSP), % xmm4, % xmm0
4008a7 : C4 E2 51 B9 44 24 40 VFMADD231SS 0x40 (% RSP), % xmm5, % xmm0
4008ae : C4 E2 49 B9 44 44 VFMADD231SS 0x44 (% rsp), % xmm6, % xmm0
4008b5 : C4 E2 41 B9 44 24 48 VFMADD231SS 0x48 (% RSP), % xmm7, % xmm0
그래서 gottrran은 루프를 풀고 7 개의 융합 된 곱하기 추가 지침을 넣습니다. 더 큰, 무작위, 다중 차원 배열을 생성하는 경우 여전히 vfmadd231s가 한 번 팝업 (그래서 루프를 unroll unroll) 팝업합니다.
다른 팁
당신이 사용하는 경우 -march=native
컴퓨터에서 사용 가능한 컴파일러,컴파일러에서 생성 SIMD 지침,지만 나는 항상 사용 -xHost
프로 ifort.
하지만 난 그렇지 않은지 어떻게 그들이 그것을 할 수 있도록"현명하게".나의 느낌에 -O3
레벨 ifort 및 하드웨어를 모두 하는 경향이 지나치게 적극적인에 벡터화(즉,사용 SIMD 기능을 보다 더 자주 그들은 한다).매우 자주를 끄는 벡터화를 얻는 가장 효율적인 코드.이것은 물론,수 있습니다 또는 사실이되지 않을 수 있습니다.
그것은 일반적으로 사용하는 것이 더 좋을 벡터는 라이브러리는 최적화 이 작업입니다.당신이 사용할 수 있는 vdmul
에 MKL 나 gsl_vector_mul
에 GSL 니다.
용 -march=NEWARCH
에 코드를 조정한 아키텍처 NEWARCH 지만에서 실행할 수 없습니다 이전 건물입니다.사용할 수 있습니다 -mtune=NEWARCH
국가 NEWARCH 는 아키텍처의 새로운 프로세서입니다.이 코드를 생성하고 튜닝을 위한 새로운 아키텍처 그러나 아직도 실행 파일이 오래된 하나입니다.지 않기 때문에 당신은 아직 새로운 기계, -mtune
아마 당신은 무엇이 필요합니다.
와 ifort 사용할 수 있는 벡터화 보고서는 플래그를 표시하는 프로그램의 일부가되었습 벡터화.예를 들어, ifort
플래그 -vec-report=1
을 줄 것이다 당신은 그러한 정보를 컴파일하는 동안.나는 확실히 있을 것이 상응하는 플래그에 추가.
gfortran 버전 sum(a*b)
것보다 더 나은 벡터화를 제공했습니다. dot_product(a,b)
오래되어 쓸모가 없습니다.표시되는 코드는 직렬 AVX2 fma 명령어를 사용하고 있습니다.
구현에 dot_product
간접 인덱싱이나 기타 복잡함(단순 루프 자체) 없이 fma는 simd 병렬 곱셈과 덧셈 명령어의 조합보다 느릴 가능성이 높습니다. 왜냐하면 곱셈은 지연 시간이 중요한 경로에서 수행될 수 있기 때문입니다.dot_product에 대한 병렬 simd fma의 gfortran 사용은 더 복잡한 경우에 매우 효과적일 수 있습니다.
다음 중 하나가 필요합니다. -O2 -ftree-vectorize -ffast-math -march=native or -O3 -ffast-math -march=native
(적절한 벡터 길이도 포함) 이를 벡터화하면 gfortran이 OpenMP 병렬 영역 내에서 벡터화하지 못할 수 있습니다.
gfortran 4.9에서는 -ftree-Vectorizer-verbose 옵션이 삭제된 것으로 보입니다.-fdump-tree-vect는 다양한 주요 gcc 버전에 대해 선택된 다른 이름을 사용하여 벡터화 패스의 세부 정보를 .vect 파일에 기록합니다.