포트란 컴파일러는 실제로 얼마나 나을까?


74

이 질문은 최근 " C ++ vs Fortran for HPC " 에 대한 답변에서 최근에 제기 된 두 가지 토론의 확장입니다 . 그리고 그것은 질문보다 조금 더 도전입니다 ...

Fortran에 유리한 주장 중 하나는 컴파일러가 더 좋다는 것입니다. 대부분의 C / Fortran 컴파일러는 동일한 백엔드를 공유하므로 두 언어에서 의미 적으로 동등한 프로그램에 대해 생성 된 코드는 동일해야합니다. 그러나 C / Fortran은 컴파일러가 최적화하기가 훨씬 쉽다고 주장 할 수 있습니다.

그래서 간단한 테스트를하기로 결정했습니다 : daxpy.fdaxpy.c 의 사본을 가지고 gfortran / gcc로 컴파일했습니다.

이제 daxpy.c는 daxpy.f (자동으로 생성 된 코드, 못생긴 것처럼)의 f2c 번역 일 뿐이므로 해당 코드를 가져 와서 조금 정리했습니다 (daxpy_c를 충족).

for ( i = 0 ; i < n ; i++ )
    dy[i] += da * dx[i];

마지막으로 gcc의 벡터 구문을 사용하여 다시 작성했습니다 (daxpy_cvec 입력).

#define vector(elcount, type)  __attribute__((vector_size((elcount)*sizeof(type)))) type
vector(2,double) va = { da , da }, *vx, *vy;

vx = (void *)dx; vy = (void *)dy;
for ( i = 0 ; i < (n/2 & ~1) ; i += 2 ) {
    vy[i] += va * vx[i];
    vy[i+1] += va * vx[i+1];
    }
for ( i = n & ~3 ; i < n ; i++ )
    dy[i] += da * dx[i];

길이가 2 인 벡터 (모든 SSE2가 허용하는)를 사용하고 한 번에 두 개의 벡터를 처리합니다. 많은 아키텍처에서 벡터 요소보다 곱셈 단위가 더 많을 수 있기 때문입니다.

모든 코드는 "-O3 -Wall -msse2 -march = native -ffast-math -fomit-frame-pointer -malign-double -fstrict-aliasing"플래그와 함께 gfortran / gcc 버전 4.5를 사용하여 컴파일되었습니다. 내 랩탑 (Intel Core i5 CPU, M560, 2.67GHz)에서 다음과 같은 출력을 얻었습니다.

pedro@laika:~/work/fvsc$ ./test 1000000 10000
timing 1000000 runs with a vector of length 10000.
daxpy_f took 8156.7 ms.
daxpy_f2c took 10568.1 ms.
daxpy_c took 7912.8 ms.
daxpy_cvec took 5670.8 ms.

따라서 원래 포트란 코드는 8.1 초보다 조금 더 걸리고, 자동 변환은 10.5 초가 걸리고, 순진한 C 구현은 7.9에서 수행하고 명시 적으로 벡터화 된 코드는 5.6에서 약간 줄어 듭니다.

그것은 포트란이 순진한 C 구현보다 약간 느리고 벡터화 된 C 구현보다 50 % 느립니다.

질문은 다음과 같습니다. 저는 네이티브 C 프로그래머이므로 해당 코드를 잘 처리했다고 확신하지만 Fortran 코드는 1993 년에 마지막으로 다루어 졌으므로 약간 오래된 것일 수 있습니다. Fortran에서 다른 사람들처럼 편안한 코딩을 느끼지 못하기 때문에 누구나 두 가지 C 버전에 비해 더 나은 작업을 수행 할 수 있습니까?

또한 누구나 icc / ifort로이 테스트를 시도 할 수 있습니까? 벡터 구문이 작동하지 않을 수도 있지만 순진한 C 버전이 어떻게 작동하는지 궁금합니다. xlc / xlf가있는 사람도 마찬가지입니다.

소스와 Makefile을 여기에 업로드했습니다 . 정확한 타이밍을 얻으려면 test.c의 CPU_TPS를 CPU의 Hz 수로 설정하십시오. 버전에 대한 개선 사항이 있으면 여기에 게시하십시오!

최신 정보:

온라인으로 파일에 stali의 테스트 코드를 추가하고 C 버전으로 보완했습니다. 이전 테스트와 일치하도록 길이가 10'000 인 벡터에서 1'000'000 루프를 수행하도록 프로그램을 수정했습니다. 암호). 숫자가 조금 작아 -par-threshold:50졌으므로 컴파일러를 병렬화 할 수있는 옵션 을 사용했습니다 . 사용 된 icc / ifort 버전은 12.1.2 20111128이며 결과는 다음과 같습니다.

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./icctest_c
3.27user 0.00system 0:03.27elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./icctest_f
3.29user 0.00system 0:03.29elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./icctest_c
4.89user 0.00system 0:02.60elapsed 188%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./icctest_f
4.91user 0.00system 0:02.60elapsed 188%CPU

요약하면 결과는 모든 실제적인 목적으로 C 및 Fortran 버전에서 동일하며 두 코드는 자동으로 병렬화됩니다. 이전 테스트에 비해 빠른 시간은 단 정밀도 부동 소수점 산술을 사용하기 때문입니다!

최신 정보:

증거의 부담이 어디로 가는지는 마음에 들지 않지만, stali의 행렬 곱셈 예제 를 C로 다시 코딩 하여 의 파일에 추가했습니다 . 다음은 하나 및 두 개의 CPU에 대한 트리플 루프의 결과입니다.

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 2500
 triple do time   3.46421700000000     
3.63user 0.06system 0:03.70elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_c 2500
triple do time 3.431997791385768
3.58user 0.10system 0:03.69elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 2500
 triple do time   5.09631900000000     
5.26user 0.06system 0:02.81elapsed 189%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_c 2500
triple do time 2.298916975280899
4.78user 0.08system 0:02.62elapsed 184%CPU

참고 cpu_time포트란은 CPU 시간이 아닌 벽 시계 시간을 measuers, 그래서에서 전화를 감싸 time2 개의 CPU 그들을 비교. C 버전이 두 개의 코어에서 약간 나아진다는 점을 제외하고는 결과간에 실제 차이가 없습니다.

matmul명령은 C에서 사용할 수 없으므로 Fortran에서만 명령 을 수행하십시오 .

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 2500
 matmul    time   23.6494780000000     
23.80user 0.08system 0:23.91elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 2500
 matmul    time   26.6176640000000     
26.75user 0.10system 0:13.62elapsed 197%CPU

와. 그것은 절대적으로 끔찍합니다. 아무도 내가 뭘 잘못하고 있는지 알 수 있습니까, 아니면 왜이 본질적인 것이 여전히 좋은지 설명 할 수 있습니까?

dgemm인텔 MKL에서 동일한 기능에 대한 라이브러리 호출이므로 벤치 마크에 호출을 추가하지 않았습니다 .

향후 테스트를 위해 C에서 Fortran보다 느린 것으로 알려진 예제를 제안 할 수 있습니까?

최신 정보

matmul작은 행렬 에서 내장 함수가 명시 적 행렬 곱보다 빠르다는 stali의 주장을 확인 하기 위해 필자는 자체 코드를 수정하여 각 방법을 사용하여 100x100 크기의 행렬을 각각 10,000 회 곱했습니다. 하나와 두 개의 CPU에서 결과는 다음과 같습니다.

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 10000 100
 matmul    time   3.61222500000000     
 triple do time   3.54022200000000     
7.15user 0.00system 0:07.16elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 10000 100
 matmul    time   4.54428400000000     
 triple do time   4.31626900000000     
8.86user 0.00system 0:04.60elapsed 192%CPU

최신 정보

Grisu는 최적화없이 gcc가 복잡한 숫자에 대한 연산을 라이브러리 함수 호출로 변환하는 반면 gfortran은 몇 가지 명령으로 인라인을 수행한다는 점을 지적합니다.

옵션 -fcx-limited-range이 설정 되면 C 컴파일러는 동일한 소형 코드를 생성합니다 . 즉, 컴파일러는 중간 값에서 오버 플로우 / 언더 플로우 가능성을 무시하도록 지시받습니다. 이 옵션은 gfortran에서 기본적으로 설정되며 잘못된 결과를 초래할 수 있습니다. -fno-cx-limited-rangegfortran을 강요 해도 아무런 변화가 없었습니다.

따라서 이것은 실제로 수치 계산에 gfortran을 사용 하는 것에 반대 하는 주장입니다 . 정확한 결과가 부동 소수점 범위 내에 있더라도 복잡한 값에 대한 연산이 오버 플로우 / 언더 플로 일 수 있습니다. 이것은 실제로 포트란 표준입니다. gcc 또는 일반적으로 C99에서 달리 지정되지 않는 한 기본값은 엄격하게 (IEEE-754 호환) 읽습니다.

주의 사항 : 주요 질문은 Fortran 컴파일러가 C 컴파일러보다 더 나은 코드를 생성하는지 여부입니다. 이것은 한 언어의 일반적인 장점과 다른 언어의 장점에 관한 토론의 장소가 아닙니다. 내가 정말로 관심을 가질만한 것은 누군가가 명시 적 벡터화를 사용하여 C에서와 같이 효율적으로 덱스 피를 생성하기 위해 gfortran을 동축하는 방법을 찾을 수 있다면 SIMD 최적화를 위해 독점적으로 컴파일러에 의존 해야하는 문제를 보여 주거나 Fortran 컴파일러가 C를 능가하는 경우.


타이밍 문제 중 하나는 프로세서가 주파수 스테핑 / 터보 모드를 수행하는 경우 이러한 결과가 전체적으로 나타날 수 있다는 것입니다.
Bill Barth 2012

1
귀하의 daxpy_c.c는 현재 X의 배수와 X를 업데이트하고 모든 y를 접촉하지 않습니다. 당신은 그것을 공정하게 만들기 위해 고칠 수 있습니다 ...
Jack Poulson

1
@ JackPoulson : 좋은 캐치, 결과 수정 및 업데이트.
Pedro

2
또한 차이점은 컴파일러를 혼란스럽게하는 Fortran 버전의 수동 언 롤링으로 인한 것입니다. C 버전에 넣은 것과 동일한 간단한 루프로 교체하면 둘 사이의 성능이 거의 동일합니다. 변경 사항이 없으면 인텔 컴파일러에서 포트란 버전이 느려졌습니다.
Jack Poulson

1
@permeakra : 실제로, C99 표준 restrict은 배열이 다른 데이터 구조와 겹치지 않는다고 가정하기 위해 컴파일러에게 정확하게 알려주 는 키워드를 지정합니다 .
Pedro

답변:


37

타이밍 차이는 단위 보행기 Fortran daxpy 의 수동 풀림 으로 인한 것 같습니다 . 다음 타이밍은 명령을 사용하여 2.67GHz Xeon X5650에 있습니다.

./test 1000000 10000

인텔 11.1 컴파일러

수동 언 롤링시 포트란 : 8.7 초 수동 언 롤링시
포트란 : 5.8 초
C 수동 언 롤링 제외시 : 5.8 초

GNU 4.1.2 컴파일러

수동 언 롤링시 포트란 : 8.3 초 수동 언 롤링 제외시
포트란 : 13.5 초
C 수동 언 롤링 제외시 : 13.6 초
C 벡터 속성 사용시 : 5.8 초

GNU 4.4.5 컴파일러

수동 풀림이있는 포트란 : 8.1 초 수동 풀림이없는
포트란 : 7.4 초
C 수동 풀림이없는 상태 : 8.5 초
C 벡터 변속기 포함 : 5.8 초

결론

  • 수동 언 롤링은이 아키텍처에서 GNU 4.1.2 Fortran 컴파일러에 도움이되었지만 최신 버전 (4.4.5)과 Intel Fortran 컴파일러에는 영향을 미치지 않습니다.
  • GNU 4.4.5 C 컴파일러는 버전 4.2.1보다 Fortran과 훨씬 더 경쟁력이 있습니다.
  • 벡터 내장 함수를 사용하면 GCC 성능이 인텔 컴파일러와 일치 할 수 있습니다.

dgemv 및 dgemm과 같은 더 복잡한 루틴을 테스트 할 시간이 있습니까?


결과 주셔서 감사합니다! gcc의 어떤 버전을 사용하고 있으며 CPU에 대해 좀 더 구체적 일 수 있습니까?
Pedro

2
컴파일러가 CPU보다 오래되었습니다. gcc-4.5로 시도해 볼 수 있습니까?
Pedro

1
방금 시도했습니다. GCC 4.4.5가 포함 된 벡터화 된 버전은 Intel 11.1 결과와 정확히 일치합니다.
잭 폴슨

1
방금 gcc / gfortran 버전 4.4.5를 설치했는데 언 롤링과의 차이점을 재현 할 수 없습니다. 실제로 두 경우 모두에 대해 생성 된 어셈블러에서 사용되는 레지스터 이름을 제외하고 가장 안쪽의 루프는 동일합니다 (교환 가능). 확실하게 테스트를 다시 실행할 수 있습니까?
Pedro

4
이런 종류의 오래된 토론이 "성능이 뛰어 나기 때문에 포트란을 계속 사용한다"고 결론을 내릴 수 있을까요? 결국 쓰레기통에 버릴 수 있을까요?
Stefano Borini

16

나는이 파티에 늦게 올 것이다. 그래서 나는 위로부터 앞뒤로 따라 가기가 어렵다. 질문은 크며, 관심이 있다면 더 작은 조각으로 나눌 수 있다고 생각합니다. 내가 관심있어 한 가지는 단순히 daxpy변형 의 성능 과 Fortran 이이 간단한 코드에서 C보다 느린 지 여부입니다.

내 랩탑 (Macbook Pro, Intel Core i7, 2.66 GHz)에서 모두 실행하는 경우 수동 벡터화 C 버전과 수동 벡터화되지 않은 Fortran 버전의 상대적 성능은 사용하는 컴파일러에 따라 다릅니다 (자체 옵션 사용).

Compiler     Fortran time     C time
GCC 4.6.1    5408.5 ms        5424.0 ms
GCC 4.5.3    7889.2 ms        5532.3 ms
GCC 4.4.6    7735.2 ms        5468.7 ms

따라서 GCC가 4.6 분기의 루프를 벡터화하는 데 이전보다 더 나은 것으로 보입니다.


전반적인 논쟁에서, 나는 어셈블리 언어에서와 마찬가지로 C와 Fortran에서 빠르고 최적화 된 코드를 작성할 수 있다고 생각합니다. 그러나 한 가지 지적 할 것입니다. 어셈블러가 C보다 작성하는 것이 더 지루하지만 CPU가 실행하는 것을 더 세밀하게 제어하는 ​​것처럼 C는 Fortran보다 저수준입니다. 따라서 Fortran 표준 구문 (또는 공급 업체 확장 기능)에 기능이 부족한 부분을 최적화하여 세부 사항을보다 효과적으로 제어 할 수 있습니다. 한 가지 경우는 벡터 유형을 명시 적으로 사용하는 것이고 다른 하나는 변수를 손으로 정렬 할 수있는 가능성이며, 포트란에서는 불가능한 것입니다.


Scicomp에 오신 것을 환영합니다! 이 경우 컴파일러 버전이 언어만큼 중요하다는 데 동의합니다. 마지막 문장에서 'off'대신 'of'를 의미 했습니까?
Aron Ahmadia 2019

9

Fortran에서 AXPY를 작성하는 방법은 약간 다릅니다. 수학의 정확한 번역입니다.

m_blas.f90

 module blas

   interface axpy
     module procedure saxpy,daxpy
   end interface

 contains

   subroutine daxpy(x,y,a)
     implicit none
     real(8) :: x(:),y(:),a
     y=a*x+y
   end subroutine daxpy

   subroutine saxpy(x,y,a)
     implicit none
     real(4) :: x(:),y(:),a
     y=a*x+y
   end subroutine saxpy

 end module blas

이제 프로그램에서 위의 루틴을 호출 해 봅시다.

test.f90

 program main

   use blas
   implicit none

   real(4), allocatable :: x(:),y(:)
   real(4) :: a
   integer :: n

   n=1000000000
   allocate(x(n),y(n))
   x=1.0
   y=2.0
   a=5.0
   call axpy(x,y,a)
   deallocate(x,y)

 end program main

이제 컴파일하고 실행하자 ...

login1$ ifort -fast -parallel m_blas.f90 test.f90
ipo: remark #11000: performing multi-file optimizations
ipo: remark #11005: generating object file /tmp/ipo_iforttdqZSA.o

login1$ export OMP_NUM_THREADS=1
login1$ time ./a.out 
real    0 m 4.697 s
user    0 m 1.972 s
sys     0 m 2.548 s

login1$ export OMP_NUM_THREADS=2
login1$ time ./a.out 
real    0 m 2.657 s
user    0 m 2.060 s
sys     0 m 2.744 s

루프 나 명시 적 OpenMP 지시문을 사용하지 않습니다 . C에서 가능합니까 (즉, 루프를 사용하지 않고 자동 병렬화하지 않습니까)? 나는 C를 사용하지 않으므로 알 수 없습니다.


자동 병렬화는 언어가 아닌 Intel 컴파일러 (Fortran 및 C)의 기능입니다. 따라서 C의 동등한 항목도 병렬화되어야합니다. 호기심만으로, 더 적당한 n = 10000에서 어떻게 수행합니까?
Pedro

3
그게 요점입니다. Fortran (C와 달리)은 matmult, transpose 등과 같은 전체 배열 연산을 지원하므로 Fortran에서 Autopar가 더 쉽습니다. 따라서 Fortran 컴파일러의 경우 코드 최적화가 더 쉽습니다. GFortran (사용한)에는 Fortran 컴파일러를 최적화 할 수있는 개발자 리소스가 없습니다. 현재 초점은 최적화가 아닌 Fortran 2003 표준을 구현하는 데 있습니다.
stali

음 ... 인텔 C / C ++ 컴파일러 icc는 자동 병렬화도 수행합니다. icctest.c다른 소스에 파일 을 추가했습니다 . 위에서 사용한 것과 동일한 옵션으로 컴파일하여 실행하고 타이밍을보고 할 수 있습니까? gcc가 모든 것을 최적화하지 않도록 코드에 printf-statement를 추가해야했습니다. 이것은 단지 빠른 해킹이며 버그가 없기를 바랍니다.
Pedro

최신 icc / ifort 컴파일러를 다운로드하여 직접 테스트했습니다. 이 새로운 결과를 포함하도록 질문이 업데이트되었습니다. 즉, 인텔의 자동 벡터화가 포트란과 C에서 모두 작동한다는 것입니다.
Pedro

1
감사. 예, 루프가 단순하고 작업이 레벨 1 BLAS이기 때문에 차이가 거의 없음을 알았습니다. 그러나 이전에 Fortran의 전체 배열 작업을 수행하고 PURE / ELEMENTAL과 같은 키워드를 사용할 수 있기 때문에 컴파일러 최적화의 여지가 더 많습니다. 컴파일러가이 정보를 사용하는 방법과 실제로하는 일은 다릅니다. 당신은 또한 당신이 원하는 경우에 matmul 시도 할 수 bpaste.net/show/23035
stali

6

컴파일러가 최신 하드웨어에 맞게 코드를 최적화하는 방법 만 흥미롭지는 않다고 생각합니다. 특히 GNU C와 GNU Fortran 사이에서 코드 생성은 매우 다를 수 있습니다.

차이점을 보여주는 또 다른 예를 살펴 보겠습니다.

복소수를 사용하는 GNU C 컴파일러는 복소수에 대한 거의 기본적인 산술 연산을 위해 큰 오버 헤드를 생성합니다. 포트란 컴파일러는 훨씬 더 나은 코드를 제공합니다. 포트란에서 다음과 같은 작은 예를 살펴 보겠습니다.

COMPLEX*16 A,B,C
C=A*B

(gfortran -g -o complex.fo -c complex.f95; objdump -d -S complex.fo)를 제공합니다.

C=A*B
  52:   dd 45 e0                fldl   -0x20(%ebp)
  55:   dd 45 e8                fldl   -0x18(%ebp)
  58:   dd 45 d0                fldl   -0x30(%ebp)
  5b:   dd 45 d8                fldl   -0x28(%ebp)
  5e:   d9 c3                   fld    %st(3)
  60:   d8 ca                   fmul   %st(2),%st
  62:   d9 c3                   fld    %st(3)
  64:   d8 ca                   fmul   %st(2),%st
  66:   d9 ca                   fxch   %st(2)
  68:   de cd                   fmulp  %st,%st(5)
  6a:   d9 ca                   fxch   %st(2)
  6c:   de cb                   fmulp  %st,%st(3)
  6e:   de e9                   fsubrp %st,%st(1)
  70:   d9 c9                   fxch   %st(1)
  72:   de c2                   faddp  %st,%st(2)
  74:   dd 5d c0                fstpl  -0x40(%ebp)
  77:   dd 5d c8                fstpl  -0x38(%ebp)

39 바이트 머신 코드입니다. C에서 같은 것을 고려할 때

 double complex a,b,c; 
 c=a*b; 

출력을 살펴보십시오 (위와 같은 방식으로 수행됨).

  41:   8d 45 b8                lea    -0x48(%ebp),%eax
  44:   dd 5c 24 1c             fstpl  0x1c(%esp)
  48:   dd 5c 24 14             fstpl  0x14(%esp)
  4c:   dd 5c 24 0c             fstpl  0xc(%esp)
  50:   dd 5c 24 04             fstpl  0x4(%esp)
  54:   89 04 24                mov    %eax,(%esp)
  57:   e8 fc ff ff ff          call   58 <main+0x58>
  5c:   83 ec 04                sub    $0x4,%esp
  5f:   dd 45 b8                fldl   -0x48(%ebp)
  62:   dd 5d c8                fstpl  -0x38(%ebp)
  65:   dd 45 c0                fldl   -0x40(%ebp)
  68:   dd 5d d0                fstpl  -0x30(%ebp)

39 바이트 머신 코드도 있지만 기능 단계 57에서 참조하는 작업의 적절한 부분을 수행하고 원하는 작업을 수행합니다. 따라서 다중 작업을 실행하기위한 27 바이트 기계 코드가 있습니다. 뒤에있는 함수는 muldc3에서 제공 libgcc_s.so하며 머신 코드에서 1375 바이트의 풋 프린트를 갖습니다. 이로 인해 코드 속도가 크게 느려지고 프로파일 러를 사용할 때 흥미로운 결과를 얻을 수 있습니다.

위의 BLAS 예제를 구현하고 zaxpy동일한 테스트를 수행 할 때 Fortran 컴파일러는 C 컴파일러보다 더 나은 결과를 제공해야합니다.

(이 실험에는 GCC 4.4.3을 사용했지만 다른 GCC가이 동작을 수행하는 것으로 나타났습니다.)

제 생각에는 병렬화와 벡터화에 대해서만 생각할 필요가 없습니다. 컴파일러가 어느 쪽이 더 나은 컴파일러인지 생각할 때 기본적인 것들이 어셈블러 코드로 어떻게 변환되는지 살펴 봐야합니다. 이 변환이 잘못된 코드를 제공하면 최적화는이 항목 만 입력으로 사용할 수 있습니다.


1
방금 코드 줄을 따라 예제를 작성하여 complex.c온라인으로 코드에 추가했습니다. 아무것도 최적화되지 않도록 모든 입 / 출력을 추가해야했습니다. 을 __muldc3사용하지 않으면 전화를받습니다 -ffast-math. 와 -O2 -ffast-math나는 인라인 어셈블러의 9 개 라인을 얻을. 이것을 확인할 수 있습니까?
Pedro

생성 된 어셈블러의 차이점에 대한 더 구체적인 원인을 발견하고 위의 질문에 이것을 추가했습니다.
Pedro

컴파일러가 -O2를 사용하면 런타임에 가능한 모든 것을 계산하도록 컴파일러가 만들어 지므로 이러한 구문이 손실되는 경우가 있습니다. 출력에 의존하려는 경우 과학 컴퓨팅에서 -ffast-math 옵션을 사용해서는 안됩니다.
MK 일명 Grisu

1
글쎄, 그 인수 (no -ffast-math)에 의해 복잡한 값 계산에 Fortran을 사용해서는 안됩니다. 내 질문에 대한 업데이트 -ffast-math또는 더 일반적으로 -fcx-limited-rangegcc가 Fortran의 표준 과 동일한 비 IEEE 제한 범위 계산을 사용하도록 강요 합니다. 따라서 복잡한 값의 전체 범위와 올바른 Infs 및 NaN을 원한다면 Fortran을 사용해서는 안됩니다.
Pedro

2
@Pedro : GCC가 GFortran wrt처럼 동작하도록하려면 복잡한 곱셈과 나눗셈을하려면 -fcx-fortran-rules를 사용해야합니다.
janneb

4

사람들,

이 토론이 매우 흥미로 웠지만 Matmul 예제에서 루프를 재정렬하면 그림이 바뀌는 것을보고 놀랐습니다. 현재 컴퓨터에 인텔 컴파일러를 사용할 수 없으므로 gfortran을 사용하고 있지만 mm_test.f90에서 루프를 다시 작성하십시오.

call cpu_time(start)  
do r=1,runs  
  mat_c=0.0d0  
     do j=1,n  
        do k=1,n  
  do i=1,n  
           mat_c(i,j)=mat_c(i,j)+mat_a(i,k)*mat_b(k,j)  
        end do  
     end do  
  end do  
end do  
call cpu_time(finish)  

내 컴퓨터의 전체 결과가 변경되었습니다.

이전 버전 타이밍 결과는 다음과 같습니다.

#time ./mm_test_f 10000 100
 matmul    time   6.3620000000000001     
 triple do time   21.420999999999999     

반면 트리플 루프는 위와 같이 재정렬됩니다.

#time ./mm_test_f 10000 100
 matmul    time   6.3929999999999998     
 triple do time   3.9190000000000005    

인텔 ® 코어 TM i7-2600K CPU (3.40GHz)의 gcc / gfortran 4.7.2 20121109입니다.

사용 된 컴파일러 플래그는 내가 여기에있는 Makefile의 플래그였습니다 ...


3
메모리의 매트릭스 스토리지가 한 순서를 선호하기 때문에, 즉 행이 연속적으로 저장되는 경우 가장 안쪽에 행을 반복하는 것이 좋습니다. 그러므로 반복적으로로드하는 것보다 빠른 로컬 메모리에 각 행을 한 번로드 할 수 있기 때문입니다. ) 단일 요소에 액세스합니다. stackoverflow.com/questions/7395556을 참조하십시오 .
Christian Clason

"내장 matmul"이 이런 식으로 일하도록 코딩되지 않았다는 것에 놀랐습니다. 트리플 방식으로 두 번째 방식으로 주문하면 훨씬 빠릅니다. 이 컴파일러 세트에있는 것처럼 보입니다. 이전 gfortran 버전에서는 타이밍이 더 평평 해졌습니다. 여러분이 어떤 방식으로 수행했는지는 중요하지 않습니다. 거의 동일한 시간이 걸렸습니다.
Schatzi

-2

도움이 되긴하지만 코드 실행 속도를 높이는 것은 언어가 아닙니다. 코드를 더 빠르게 실행하는 것은 컴파일러, CPU 및 운영 체제입니다. 언어를 비교하는 것은 단지 잘못되고 쓸모없고 의미가 없습니다. 언어와 컴파일러의 두 변수를 비교하기 때문에 의미가 없습니다. 하나의 코드가 더 빨리 실행되면 언어가 얼마인지 또는 컴파일러가 얼마인지 알 수 없습니다. 왜 컴퓨터 과학 커뮤니티가 이것을 이해하지 못하는지 이해하지 못합니다 :-(

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.