Fortran derleyicileri gerçekte ne kadar iyidir?


74

Bu soru, son zamanlarda " C ++ vs Fortran for HPC " yanıtlarına gelen iki tartışmanın bir uzantısı . Ve bu bir sorudan biraz daha zor.

Fortran lehine en sık duyulan tartışmalardan biri, derleyicilerin daha iyi olduğu yönünde. Çoğu C / Fortran derleyicisi aynı arka ucu paylaştığından, her iki dilde de semantik olarak eşdeğer programlar için oluşturulan kod aynı olmalıdır. Bununla birlikte, C / Fortran'ın derleyicinin optimizasyonu için daha fazla / daha az daha kolay olduğu iddia edilebilir.

Böylece basit bir test yapmaya karar verdim: daxpy.f ve daxpy.c'nin bir kopyasını aldım ve onları gfortran / gcc ile derledim.

Şimdi daxpy.c daxpy.f'in bir f2c çevirisidir (otomatik olarak oluşturulan kod, çirkin gibi çirkin), bu yüzden bu kodu aldım ve biraz temizledik (daxpy_c ile karşılaştığım), bu temelde en içteki döngüyü yeniden yazmak anlamına geliyordu.

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

Sonunda, gcc'nin vektör sözdizimini kullanarak yeniden yazdım (daxpy_cvec yazın):

#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];

Unutmayın, uzunluk 2 vektörleri (hepsi SSE2'nin izin verdiği) kullandığımı ve aynı anda iki vektörü işlediğime dikkat edin. Bunun nedeni birçok mimaride, vektör elementlerimizden daha fazla çarpma birimine sahip olabileceğimizdir.

Tüm kodlar "-O3 -Wall -msse2 -march = native -ffast-math -fomit-frame-pointer-malign-double -fstrict-aliasing" bayraklarıyla gfortran / gcc versiyon 4.5 kullanılarak derlendi. Dizüstü bilgisayarımda (Intel Core i5 CPU, M560, 2.67GHz) Aşağıdaki çıktıyı aldım:

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.

Bu yüzden, orijinal Fortran kodu 8.1 saniyeden biraz daha fazla sürüyor, otomatik çevirisi 10.5 saniye sürüyor, saf C uygulaması 7.9'da ve açıkça vektörelleştirilmiş kod 5.6'da az da olsa yapıyor.

Bu Fortran'ın saf C uygulamasından biraz daha yavaş ve vectorized C uygulamasından% 50 daha yavaş olması.

İşte soru şu: Ben yerel bir C programcısıyım ve bu yüzden bu kod üzerinde iyi bir iş yaptığımdan eminim, ancak Fortran koduna en son 1993 yılında dokunulmuştu ve bu nedenle biraz eski olabilir. Fortran'da diğerlerinin yapabileceği kadar rahat bir kodlama hissetmediğim için, herkes daha iyi bir iş yapabilir mi, yani iki C versiyonundan birine göre daha rekabetçi mi?

Ayrıca, herhangi biri bu testi icc / ifort ile deneyebilir mi? Vektör sözdizimi muhtemelen işe yaramaz, ancak saf C sürümünün orada nasıl davrandığını görmek isterim. Aynı xlc / xlf etrafında yatan herkes için de geçerlidir.

Kaynakları ve bir Makefile'i buraya yükledim . Doğru zamanlamaları almak için, test.c'deki CPU_TPS'yi CPU'nuzdaki Hz sayısına ayarlayın. Herhangi bir sürümünde herhangi bir gelişme bulursanız, lütfen onları buraya gönderin!

Güncelleme:

Stali'nin test kodunu çevrimiçi olarak dosyalara ekledim ve C sürümüyle tamamladım. Programları, önceki testle tutarlı olacak şekilde 10'000 uzunluğunda vektörler üzerinde 1'000'000 döngü yapacak şekilde değiştirdim (ve makinem stali'nin orijinalinde olduğu gibi 1'000'000'000 uzunluğunda vektörler atayamıyordu. kodu). Rakamlar şimdi biraz daha küçük olduğundan, -par-threshold:50derleyiciyi paralelleştirme olasılığını artırmak için bu seçeneği kullandım . Kullanılan icc / ifort versiyonu 12.1.2 20111128 ve sonuçları aşağıdaki gibidir.

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

Özet olarak, sonuçlar, tüm pratik amaçlar için, hem C hem de Fortran versiyonları için aynıdır ve her iki kod da otomatik olarak paraleldir. Önceki teste kıyasla hızlı sürelerin, tek kesinlikli kayar nokta aritmetiğinden kaynaklandığını unutmayın!

Güncelleme:

Burada ispat külfetinin nereye gittiğini pek sevmesem de, stali'nin matris çarpma örneğini C olarak yeniden kodladım ve web'deki dosyalara ekledim . İşte bir ve iki CPU için üçlü döngü sonuçları:

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

Not cpu_timeFortranda CPU zamanı değil duvar saatlik zaman hasta veri formu, o yüzden içeri aramaları sarılı time2 işlemciler için bunları karşılaştırmak. C sürümünün iki çekirdek üzerinde biraz daha iyi olması dışında, sonuçlar arasında gerçek bir fark yoktur.

Şimdi matmulkomut için, tabii ki sadece Fortran'da bu içsel C'de bulunmaz.

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

Vay. Bu kesinlikle korkunç. Birisi ya yanlış yaptığımı öğrenebilir ya da neden bu içselliğin hala bir şekilde iyi bir şey olduğunu açıklayabilir mi?

Ben eklemek vermedi dgemmonlar Intel MKL aynı işleve kütüphane çağrıları gibi kıyaslama çağrıları.

Gelecekteki testler için, C’de Fortran’dan daha yavaş olduğu bilinen bir örnek önerilebilir mi?

Güncelleme

matmulStali'nin içsel olanın, daha küçük matrislerdeki açık matris ürününden daha hızlı bir "mıknatıs sırası" olduğunu iddia etmek için , her iki yöntemi de kullanarak her biri 10'000 kez olan 100x100 boyutundaki matrisleri çarpmak için kendi kodunu değiştirdim. Bir ve iki CPU üzerindeki sonuçlar aşağıdaki gibidir:

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

Güncelleme

Grisu, optimizasyonlar olmadan, gcc'nin karmaşık sayılardaki işlemleri kütüphane işlev çağrılarına dönüştürdüğü, gfortran'ın birkaç talimat içerdiği anlamına geldiğine işaret etmekte haklıdır.

Eğer seçenek -fcx-limited-rangeayarlanmışsa C derleyici aynı kompakt kodu üretecektir , yani derleyiciye ara değerlerdeki potansiyel aşırı / düşük akışları görmezden gelmesi talimatı verilmiştir. Bu seçenek bir şekilde varsayılan olarak gfortran'da ayarlanmıştır ve yanlış sonuçlara yol açabilir. Gfortran'a zorlamak -fno-cx-limited-rangehiçbir şeyi değiştirmedi.

Dolayısıyla bu, sayısal hesaplamalar için gfortran kullanımına karşı bir argümandır : Karmaşık değerler üzerinde yapılan işlemler, doğru sonuçlar kayan nokta aralığında olsa bile, aşırı / düşük olabilir. Bu aslında bir Fortran standardıdır. Gcc'de veya genel olarak C99'da varsayılan, aksi belirtilmediği sürece işleri kesin yapmaktır (IEEE-754 uyumlu olanları okuyun).

Hatırlatma: Lütfen asıl sorunun Fortran derleyicilerinin C derleyicilerden daha iyi kod üretip üretmediği olduğunu unutmayın. Burası, bir dilin genel yararına ilişkin tartışmaların yeri değil. Gerçekten ilgilendiğim şey, herhangi birinin, yalnızca SIMD optimizasyonu için derleyiciye güvenmek zorunda olma problemlerini örneklendirdiği gibi açık bir vektörlemeyi kullanarak C'deki kadar verimli bir dakspy üretecek bir gutkanın bir eşekarısı oluşturmasının bir yolunu bulabilmesidir. Bir Fortran derleyicisinin C karşılığını çıkardığı durumda.


Bir zamanlama sorunu, eğer işlemciniz frekans adımlama / turbo modunu yaparsa, bu sonuçların haritanın her yerinde olabileceğidir.
Bill Barth,

1
Kişisel daxpy_c.c şu anda x katları ile x güncellenmesi ve hiç y dokunmuyor. Bunu adil kılmak için düzeltmek isteyebilirsiniz ...
Jack Poulson

1
@ JackPoulson: İyi yakalama, sabit ve sonuçları güncellendi.
Pedro,

2
Ayrıca, farkın, Fortran sürümündeki derleyiciyi karıştıran el kitabının açılması nedeniyle tamamen farklı olduğundan eminim. C sürümünüze koyduğunuz aynı basit döngü ile değiştirdiğimde, ikisi arasındaki performans neredeyse aynı. Değişim olmadan, Fortran sürümü Intel derleyicileriyle daha yavaştı.
Jack Poulson

1
@permeakra: Aslında, C99 standardı restrict, derleyiciye tam olarak şunu söyleyen anahtar kelimeyi belirtir : bir dizinin başka bir veri yapısıyla çakışmadığını varsaymak için.
Pedro,

Yanıtlar:


37

Zamanlamalarınızdaki fark , birim adım Fortran daxpy'nin manuel olarak açılması nedeniyle görünüyor . Aşağıdaki zamanlamalar, komut kullanılarak 2.67 GHz Xeon X5650’de

./test 1000000 10000

Intel 11.1 derleyicileri

El ile açılması ile Fortran: 8.7 saniye El ile açılması ile
Fortran elle açma: 5.8 saniye
C ile elle açma: 5.8 saniye

GNU 4.1.2 derleyicileri

8.3 sn: Manuel Açma elemanı ile Fortran
el Açma elemanı o / w Fortran: 13.5 sn
C kılavuzu sarılmasını w / o: 13.6 sn
vektörü C özellikleri: 5.8 sn

GNU 4.4.5 derleyicileri

Kılavuzu Açma elemanı ile Fortran 8.1 sn
Fortran ağırlık / el sarılmasını O: 7.4 sn
C w el sarılmasını / o: 8.5 sn
vektör atrributes C: 5.8 sn

Sonuçlar

  • El ile açma, bu mimarideki GNU 4.1.2 Fortran derleyicilere yardımcı oldu, ancak daha yeni sürümü (4.4.5) ve Intel Fortran derleyicisini incitti.
  • GNU 4.4.5 C derleyicisi Fortran ile 4.2.1 sürümünden çok daha rekabetçi.
  • Vektörün gerçekleri, GCC performansının Intel derleyicileriyle eşleşmesini sağlar.

Dgemv ve dgemm gibi daha karmaşık rutinleri test etme zamanı geldi mi?


Sonuçlar için teşekkürler! Hangi gcc sürümünü kullanıyordunuz ve CPU ile ilgili biraz daha spesifik olabilir misiniz?
Pedro,

2
Derleyiciniz CPU'nuzdan daha eski ... gcc-4.5 ile deneyebilir misiniz?
Pedro,

1
Sadece denedim. GCC 4.4.5 içeren vectorized sürüm, Intel 11.1 sonuçlarıyla tam olarak eşleşiyor.
Jack Poulson

1
Gcc / gfortran 4.4.5 sürümünü yeni yükledim ve açılmayan farkları yeniden üretemiyorum. Aslında, her iki durumda da üretilen montajlayıcıda, en içteki döngü, değiştirilebilir olan kullanılan kayıt adları dışında aynıdır. Emin olmak için testlerini tekrar yapabilir misin?
Pedro,

4
Bu tür bir tartışmayı “daha ​​güçlü bir performans olduğu için“ fortran kullanmaya devam ediyoruz ”, böylece nihayet çöp tenekesine atabiliriz diyebilir miyiz?
Stefano Borini

16

Bu partiye geç geleceğim, bu yüzden her şeyden ileri geri takip etmek benim için zor. Soru büyük ve bence ilgilenirseniz daha küçük parçalara bölünebilir. İlgilendiğim bir şey daxpyvaryantlarınızın performansı ve Fortran'ın bu çok basit kodda C'den daha yavaş olup olmadığıydı.

Hem dizüstü bilgisayarımda (Macbook Pro, Intel Core i7, 2.66 GHz) çalışırsanız, elle vectorized C sürümünüzün ve elle olmayan vectorized Fortran sürümünün göreceli performansı, kullanılan derleyiciye bağlıdır (kendi seçeneklerinizle):

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

Dolayısıyla, GCC'nin 4.6 dalındaki döngüyü vektörleştirmede öncekinden daha iyi olduğu görülüyor.


Genel tartışmada, sanırım hem C hem de Fortran'da hemen hemen derleme dilinde olduğu gibi hızlı ve optimize edilmiş bir kod yazabileceğini düşünüyorum. Bununla birlikte, bir şeyi işaret edeceğim: montajcı C'den daha sıkıcı olduğu gibi, ancak CPU tarafından yürütülenler üzerinde daha iyi kontrol sağladığı gibi, C de Fortran'dan daha düşük seviyededir. Bu nedenle, Fortran standart sözdiziminin (veya satıcı uzantılarının) işlevsellikten yoksun olduğu durumlarda, optimizasyona yardımcı olabilecek ayrıntılar üzerinde daha fazla kontrol sağlar. Bir örnek, vektör türlerinin açıkça kullanılması, diğeri ise Fortran'ın yapamayacağı bir şeyin el ile değişkenlerin hizalanmasını belirleme olasılığıdır.


Scicomp'e hoş geldiniz! Bu durumda derleyici sürümlerinin dil kadar önemli olduğu konusunda hemfikirim. Son cümleinizde 'yerine' yerine 'mi demek istediniz?
Aron Ahmadia,

9

AXPY'yi Fortran'da yazma biçimim biraz farklı. Bu matematiğin tam çevirisidir.

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

Şimdi bir programda yukarıdaki rutini çağıralım.

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

Şimdi derleyelim ve çalıştıralım ...

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

Herhangi bir döngü veya açık bir OpenMP yönergesi kullanmadığımı fark et. Bu C'de mümkün mü (yani, döngü kullanımı ve otomatik paralelleştirme yok)? C kullanmıyorum bu yüzden bilmiyorum.


Otomatik paralelleştirme, dilin değil Intel derleyicilerinin (hem Fortran hem de C) bir özelliğidir. Bu nedenle C'deki eşdeğeri de paralel olmalıdır. Sadece merak dışında, daha ılımlı bir n = 10000 için nasıl bir performans sergiliyor?
Pedro,

3
Bütün mesele buydu. Fortran'da (C'nin aksine) matmult, transpose vb. Gibi tüm dizi işlemlerini desteklediğinden dolayı Autopar daha kolaydır, dolayısıyla Fortran derleyicileri için kod optimizasyonu daha kolaydır. GFortran (kullanmış olduğunuz), Fortran derleyicisini en iyi duruma getirmek için geliştirici kaynaklarına sahip değil çünkü odak noktası şu anda optimizasyon yerine Fortran 2003 standardını uygulamak.
stali,

Uhmm ... Intel C / C ++ derleyicisi iccde otomatik paralelleştirme yapıyor. icctest.cDiğer kaynaklara bir dosya ekledim . Onu yukarıda kullandığınız seçeneklerle derleyebilir, çalıştırabilir ve zamanlamaları raporlayabilir misiniz? Gcc'nin her şeyi optimize etmesini önlemek için koduma bir printf-ifade eklemek zorunda kaldım. Bu sadece hızlı bir kesmek ve umarım hatasızdır!
Pedro,

En son icc / ifort derleyicilerini indirdim ve testleri kendim yaptım. Soru, bu yeni sonuçları içerecek şekilde güncellendi, yani Intel'in kendi otovektörleşmesi hem Fortran hem de C'de çalışıyor.
Pedro

1
Teşekkürler. Evet, belki de çok az fark olduğunu fark ettim, çünkü döngüler basit ve işlemler Seviye 1 BLAS. Ancak daha önce söylediğim gibi, Fortran'ın tüm dizi işlemlerini yapabilme kabiliyeti ve PURE / ELEMENTAL gibi anahtar kelimeler kullanması nedeniyle derleyici optimizasyonu için daha fazla alan var. Derleyiciler bu bilgiyi nasıl kullanır ve gerçekten yaptığı şey farklı bir şeydir. Ayrıca bpaste.net/show/23035
stali

6

Bir derleyicinin modern donanım kodunu nasıl optimize ettiği sadece ilginç değil. Özellikle GNU C ve GNU Fortran arasında kod üretimi çok farklı olabilir.

Öyleyse aralarındaki farkları göstermek için başka bir örnek ele alalım.

Karmaşık sayıları kullanarak, GNU C derleyicisi karmaşık bir sayıdaki neredeyse çok temel aritmetik işlem için büyük bir ek yük üretir. Fortran derleyicisi daha iyi kod veriyor. Fortran'daki aşağıdaki küçük örneğe bir göz atalım:

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

verir (gfortran -g-o kompleksi.fo -c kompleksi.f95; objdump -d -S kompleksi.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 bayt makine kodu. C de aynısını düşündüğümüzde

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

ve çıktıya bir göz atın (yukarıdaki gibi yapıldığı gibi):

  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 byte'lık makine kodu olan fakat adım 57'ye atıfta bulunulan işlev, işin doğru kısmını yapar ve istenen işlemi gerçekleştirir. Bu yüzden çoklu işlemi çalıştırmak için 27 byte makine kodumuz var. İşlev, muldc3 tarafından sağlanan libgcc_s.sove makine kodunda 1375 baytlık bir ayak izine sahip. Bu, kodu önemli ölçüde yavaşlatır ve bir profil oluştururken ilginç bir çıktı verir.

Yukarıdaki BLAS örneklerini uyguladığımızda zaxpyve aynı testi yaptığımızda , Fortran derleyici C derleyiciden daha iyi sonuçlar vermelidir.

(Bu deney için GCC 4.4.3 kullandım, ancak bu davranışı başka bir GCC'nin yayınladığı.)

Bu yüzden, bence, hangi derleyicinin daha iyi derleyici olduğunu düşündüğümüzde, paralelleştirici ve vektörelleştirmeyi düşünmüyoruz, ayrıca temel şeylerin assembler koduna nasıl çevrildiğine de bakmalıyız. Bu çeviri hatalı kod verirse, optimizasyon bu şeyleri yalnızca girdi olarak kullanabilir.


1
Sadece kodunuzun çizgileri boyunca bir örnek hazırladım complex.cve çevrimiçi olarak koda ekledim. Hiçbir şeyin optimize edilmediğinden emin olmak için tüm giriş / çıkışı eklemek zorunda kaldım. Sadece bir çağrı olsun __muldc3ben kullanmak istemiyorsanız -ffast-math. İle -O2 -ffast-mathben satır içine assembler 9 satır olsun. Bunu onaylayabilir misin?
Pedro,

Oluşturulan montajcıdaki fark için daha belirgin bir neden buldum ve bunu yukarıdaki soruma ekledim.
Pedro,

-O2 kullanmak, derleyicinin çalışma zamanında mümkün olan her şeyi hesaplamasını sağlar, bu nedenle bu tür yapılar bazen kaybolur. -Ffast-matem seçeneği çıktılara güvenmek istediğinizde bilimsel hesaplamada kullanılmamalıdır.
MK aka Grisu

1
Eh, bu argümanla (hayır -ffast-math), karmaşık değerli hesaplarınız için Fortran kullanmamalısınız. Soruma güncellemede açıkladığım gibi, -ffast-mathveya daha genel olarak, -fcx-limited-rangegcc'yi Fortran'da standart olanlarla aynı IEEE olmayan sınırlı seri hesaplamaları kullanmaya zorlar . Öyleyse, tüm karmaşık değerleri ve doğru Infs ve NaN'leri istiyorsanız, Fortran kullanmamalısınız ...
Pedro

2
@Pedro: GCC'nin GFortran wrt gibi davranmasını istiyorsanız. karmaşık çarpma ve bölme, -fcx-fortran-kurallarını kullanmalısınız.
janneb

4

Millet,

Bu tartışmayı çok ilginç buldum, ancak Matmul örneğindeki döngüyü tekrar sıralamanın resmi değiştirdiğini görünce şaşırdım. Mevcut makinemde bir intel compiler yok, bu yüzden gfortran kullanıyorum, ancak mm_test.f90’daki döngüler yeniden

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)  

makinemin tüm sonuçlarını değiştirdim.

Önceki sürüm zamanlama sonuçları:

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

üçlü döngüler ile yeilded olarak tekrar düzenlenmiş:

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

Bu, gcc / gfortran 4.7.2 20121109 tarihinde Intel (R) Core (TM) i7-2600K CPU @ 3.40GHz’de.

Kullanılan derleyici bayrakları buraya geldiğim Makefile'dendi ...


3
Bu şaşırtıcı değildir, çünkü bellekteki matris depolaması bir siparişi tercih eder, yani sıralar bitişik olarak depolanırsa, en içteki sıralar üzerinde döngü yapmak daha iyidir, çünkü o zaman her sırayı tekrar tekrar yükleme işlemine kıyasla bir kez hızlı yerel hafızaya yükleyebilirsiniz (bir dilim ) tek bir elemana erişmek için. Stackoverflow.com/questions/7395556 adresine bakın .
Christian Clason

Sanırım "içsel matmul" 'un işleri bu şekilde yapmak için kodlanmamasına şaşırdım. Üçlü ikinci sırada sipariş ile büyük ölçüde daha hızlı. Bu derleyici setinde göründüğü gibi, daha önceki gfortran sürümleri zamanlamaları sırasında daha "düz" olduklarından, çoğunu hangi şekilde yaptığınız önemli değildi - neredeyse aynı zaman aldı.
Schatzi

-2

Yardım etmelerine rağmen kodun daha hızlı çalışmasını sağlayan diller değil. Kodlayıcıların daha hızlı çalışmasını sağlayan derleyici, CPU ve işletim sistemidir. Dilleri karşılaştırmak işe yaramaz ve anlamsız bir yanlıştır. Herhangi bir anlamı yoktur, çünkü iki değişkeni karşılaştırıyorsunuz: dil ve derleyici. Bir kod daha hızlı çalışırsa, dilin ne kadar olduğunu veya derleyicinin ne kadar olduğunu bilmiyorsunuzdur. Bilgisayar bilimleri topluluğunun neden bunu anlamadığını anlamıyorum :-(

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.