>

AVX2 및 FMA3이있는 i5-4250U가 있습니다. 내가 작성한 Linux에서 GCC 4.8.1의 고밀도 행렬 곱셈 코드를 테스트하고 있습니다. 아래는 내가 컴파일하는 세 가지 차이점 목록입니다.

SSE2:     gcc matrix.cpp -o matrix_gcc -O3 -msse2 -fopenmp
AVX:      gcc matrix.cpp -o matrix_gcc -O3 -mavx  -fopenmp
AVX2+FMA: gcc matrix.cpp -o matrix_gcc -O3 -march=native -fopenmp -ffast-math

SSE2와 AVX 버전은 성능이 분명히 다릅니다. 그러나 AVX2 + FMA는 AVX 버전보다 좋지 않습니다. 나는 이것을 이해하지 못한다. FMA가 없다고 가정하면 CPU 피크 플롭의 80 % 이상을 얻었지만 FMA로 훨씬 더 잘 할 수 있다고 생각합니다. 행렬 곱셈은 FMA로부터 직접 이익을 얻을 수 있습니다. AVX에서 본질적으로 한 번에 8 개의 도트 제품을 수행하고 있습니다. 내가 march=native 를 확인할 때  그것은 제공합니다 :

cc -march=native -E -v - </dev/null 2>&1 | grep cc1 | grep fma 
...-march=core-avx2 -mavx -mavx2 -mfma -mno-fma4 -msse4.2 -msse4.1 ...

그래서 활성화 된 것을 볼 수 있습니다 ( -mfma 를 추가했는지 확인하십시오)  그러나 그것은 차이가 없습니다). ffast-math  편안한 부동 소수점 모델 사용 방법 SSE/AVX를 사용한 FMA (Fused Multiply-Add) 지침

수정 :

Mysticial의 의견을 바탕으로 _mm256_fmadd_ps를 사용했으며 이제 AVX2 + FMA 버전이 더 빠릅니다.컴파일러가 왜이 작업을 수행하지 않는지 잘 모르겠습니다.이제 1000x1000 이상의 매트릭스에 대해 약 80GFLOPS (FMA가없는 피크 플롭의 110 %)가 표시됩니다. 내 피크 플롭 계산을 신뢰하지 않는 사람이 여기에 내가 한 일입니다.

peak flops (no FMA) = frequency * simd_width * ILP * cores
                    = 2.3GHZ    * 8          * 2   * 2     =  73.2 GFLOPS
peak flops (with FMA) = 2 * peak flops (no FMA)            = 146.2 GFLOPS

두 코어를 모두 사용할 때 터보 모드의 CPU는 2.3GHz입니다. Ivy Bridge는 동시에 하나의 AVX 곱셈과 하나의 AVX 추가를 수행 할 수 있기 때문에 ILP에 대해 2를 얻습니다 (그리고 이것을 보장하기 위해 루프를 여러 번 풀었습니다).

FMA가있는 피크 플롭의 약 55 % 만 얻었습니다. 왜 그런지 모르겠지만 적어도 지금 무언가를보고 있습니다.

한 가지 부작용은 내가 믿는 것으로 알려진 간단한 행렬 곱셈 알고리즘과 비교할 때 작은 오류가 발생한다는 것입니다. FMA는 일반적으로 두 가지가 아닌 하나의 반올림 모드 만 가지고 있기 때문에 (IEEE 부동 소수점 규칙이 더 나은 경우에도 아이러니하게 위반합니다)

수정 :

누군가 다시 실행해야합니다 사이클 당 이론적으로 최대 4 개의 FLOP를 달성하려면 어떻게해야합니까? 그러나 Haswell을 사용하면 사이클 당 8 개의 이중 부동 소수점 FLOPS를 수행하십시오.

수정

실제로 Mysticial은 FMA3를 지원하기 위해 프로젝트를 업데이트했습니다 (위의 링크에서 그의 답변 참조). Linux 버전이 FMA 지원으로 컴파일되지 않았기 때문에 MSVC2012를 사용하여 Windows8에서 그의 코드를 실행했습니다. 결과는 다음과 같습니다.

Testing AVX Mul + Add:
Seconds = 22.7417
FP Ops  = 768000000000
FLOPs   = 3.37705e+010
sum = 17.8122
Testing FMA3 FMA:
Seconds = 22.1389
FP Ops  = 1536000000000
FLOPs   = 6.938e+010
sum = 333.309

이중 부동 소수점에 대한 FMA3의 경우 69.38 GFLOPS입니다. 단일 부동 소수점의 경우 138.76 SP GFLOPS가되도록 배가해야합니다. 내 피크는 146.2 SP GFLOPS라고 계산합니다.이것은 피크의 95 %입니다!즉, GEMM 코드를 상당히 개선 할 수 있어야합니다 (이미 Eigen보다 훨씬 빠르지 만).

  • 답변 # 1

    여기서 질문의 아주 작은 부분에만 답하십시오. _mm256_add_ps(_mm256_mul_ps(areg0,breg0), tmp0) 를 쓰면 gcc-4.9는 인라인 asm과 거의 비슷하게 처리하고 많이 최적화하지는 않습니다. areg0*breg0+tmp0 로 교체하면 , gcc와 clang에서 모두 지원되는 구문 인 경우 gcc는 최적화를 시작하고 가능한 경우 FMA를 사용할 수 있습니다. gcc-5, _mm256_add_ps 의 개선  예를 들어, 이제 + 를 사용하는 인라인 함수로 구현되었습니다. 내장 함수가있는 코드도 최적화 할 수 있습니다.

  • 답변 # 2

    다음 컴파일러 옵션은 _mm256_add_ps(_mm256_mul_ps(a, b), c) 를 계약하기에 충분합니다.  지금 단일 fma 명령어로 (예 : vfmadd213ps ) ) :

    GCC 5.3:   -O2 -mavx2 -mfma
    Clang 3.7: -O1 -mavx2 -mfma -ffp-contract=fast
    ICC 13:    -O1 -march=core-avx2
    
    

    나는 /O2 /arch:AVX2 /fp:fast 를 시도  MSVC와 계약을 맺었지만 여전히 계약되지 않습니다 (놀랍습니다). MSVC는 스칼라 연산을 계약합니다.

    GCC는 최소한 GCC 5.1부터 시작했습니다.

    <시간> 비록 pyzwyz  일부 컴파일러에서이 최적화를 위해충분입니다.항상 -O1 이상을 사용하십시오.  전체 성능을 위해, 바람직하게는 -O2  프로필 가이드 최적화도 제공합니다.

    그리고 코드에 문제가 없다면 -O3 -march=native -flto .

    -ffast-math

  • 이전 sql - 발생률 캡처
  • 다음 c++ - 함수가 제대로 작동하지 않고 디버거가 도움이되지 않습니다