Quanto sono davvero migliori i compilatori Fortran?


74

Questa domanda è un'estensione di due discussioni che sono emerse di recente nelle risposte a " C ++ vs Fortran per HPC ". Ed è un po 'più una sfida che una domanda ...

Uno degli argomenti più ascoltati a favore di Fortran è che i compilatori sono semplicemente migliori. Poiché la maggior parte dei compilatori C / Fortran condividono lo stesso back-end, il codice generato per programmi semanticamente equivalenti in entrambe le lingue dovrebbe essere identico. Si potrebbe sostenere, tuttavia, che C / Fortran è più / meno facile da ottimizzare per il compilatore.

Così ho deciso di provare un semplice test: ho ottenuto una copia di daxpy.f e daxpy.c e li ho compilati con gfortran / gcc.

Ora daxpy.c è solo una traduzione f2c di daxpy.f (codice generato automaticamente, brutto come diamine), quindi ho preso quel codice e l'ho ripulito un po '(incontra daxpy_c), che sostanzialmente significava riscrivere il ciclo più interno come

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

Infine, l'ho riscritto (inserisci daxpy_cvec) usando la sintassi vettoriale di gcc:

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

Si noti che io uso vettori di lunghezza 2 (tutto ciò che SSE2 consente) e che elaboro due vettori alla volta. Questo perché su molte architetture, potremmo avere più unità di moltiplicazione di quanto non abbiamo elementi vettoriali.

Tutti i codici sono stati compilati usando gfortran / gcc versione 4.5 con i flag "-O3 -Wall -msse2 -march = native -ffast-math -fomit-frame-pointer -malign-double -fstrict-aliasing". Sul mio laptop (CPU Intel Core i5, M560, 2,67 GHz) ho ottenuto il seguente output:

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.

Quindi il codice originale di Fortran impiega poco più di 8,1 secondi, la sua traduzione automatica dura 10,5 secondi, l'implementazione C ingenua lo fa in 7,9 e il codice esplicitamente vettoriale lo fa in 5,6, leggermente meno.

Fortran è leggermente più lento dell'implementazione C ingenua e il 50% più lento dell'implementazione C vettoriale.

Quindi ecco la domanda: sono un programmatore C nativo e quindi sono abbastanza sicuro di aver fatto un buon lavoro su quel codice, ma il codice Fortran è stato toccato l'ultima volta nel 1993 e potrebbe quindi essere un po 'obsoleto. Dato che a Fortran non mi sento a mio agio con la codifica come altri qui, qualcuno può fare un lavoro migliore, cioè più competitivo rispetto a una delle due versioni C?

Inoltre, qualcuno può provare questo test con icc / ifort? La sintassi vettoriale probabilmente non funzionerà, ma sarei curioso di vedere come si comporta l'ingenua versione C lì. Lo stesso vale per chiunque abbia xlc / xlf in giro.

Ho caricato le fonti e un Makefile qui . Per ottenere tempi precisi, impostare CPU_TPS in test.c sul numero di Hz sulla CPU. Se trovi miglioramenti a una qualsiasi delle versioni, pubblicale qui!

Aggiornare:

Ho aggiunto il codice di prova di Stali ai file online e l'ho integrato con una versione C. Ho modificato i programmi per fare 1'000'000 loop su vettori di lunghezza 10'000 per essere coerente con il test precedente (e poiché la mia macchina non è stata in grado di allocare vettori di lunghezza 1'000'000'000, come nell'originale di Stali codice). Dato che i numeri sono ora un po 'più piccoli, ho usato l'opzione -par-threshold:50per rendere più probabile il parallelismo del compilatore. La versione icc / ifort utilizzata è 12.1.2 20111128 e i risultati sono i seguenti

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

In sintesi, i risultati sono, per tutti gli scopi pratici, identici per entrambe le versioni C e Fortran, ed entrambi i codici si parallelizzano automaticamente. Si noti che i tempi rapidi rispetto al test precedente sono dovuti all'uso dell'aritmetica in virgola mobile a precisione singola!

Aggiornare:

Sebbene non mi piaccia davvero dove sta andando l'onere della prova, ho ricodificato l' esempio di moltiplicazione della matrice di Stali in C e l'ho aggiunto ai file sul web . Ecco i risultati del tripple loop per una e due 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

Si noti che cpu_timein Fortran si misura il tempo della CPU e non l'ora dell'orologio da parete, quindi ho inserito le chiamate timeper confrontarle per 2 CPU. Non c'è alcuna differenza reale tra i risultati, tranne per il fatto che la versione C fa un po 'meglio su due core.

Ora per il matmulcomando, ovviamente solo in Fortran poiché questo intrinseco non è disponibile in C:

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

Wow. È assolutamente terribile. Qualcuno può scoprire cosa sto facendo di sbagliato, o spiegare perché questo intrinseco è ancora in qualche modo una buona cosa?

Non ho aggiunto le dgemmchiamate al benchmark poiché sono chiamate in libreria alla stessa funzione in Intel MKL.

Per i test futuri, qualcuno può suggerire un esempio noto per essere più lento in C rispetto a Fortran?

Aggiornare

Per verificare l'affermazione matmuldi Stali secondo cui l' intrinseco è "un ordine di grandezza" più veloce del prodotto a matrice esplicita su matrici più piccole, ho modificato il suo codice per moltiplicare matrici di dimensioni 100x100 usando entrambi i metodi, 10'000 volte ciascuno. I risultati, su una e due CPU, sono i seguenti:

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

Aggiornare

Grisu ha ragione nel sottolineare che, senza ottimizzazioni, gcc converte le operazioni su numeri complessi in chiamate di funzioni di libreria mentre gfortran le inserisce in alcune istruzioni.

Il compilatore C genererà lo stesso codice compatto se l'opzione -fcx-limited-rangeè impostata, ovvero al compilatore viene richiesto di ignorare i potenziali over / under -flow nei valori intermedi. Questa opzione è in qualche modo impostata di default in gfortran e può portare a risultati errati. La forzatura -fno-cx-limited-rangein gfortran non ha cambiato nulla.

Quindi, questo è in realtà un argomento contro l' uso di gfortran per i calcoli numerici: le operazioni su valori complessi possono over / under-flow anche se i risultati corretti sono all'interno dell'intervallo in virgola mobile. Questo è in realtà uno standard Fortran. In gcc, o in C99 in generale, il default è fare le cose rigorosamente (leggi conforme IEEE-754) se non diversamente specificato.

Promemoria: tieni presente che la domanda principale era se i compilatori Fortran producessero un codice migliore rispetto ai compilatori C. Questo non è il luogo per discussioni sui meriti generali di una lingua rispetto a un'altra. Quello a cui sarei davvero interessato è se qualcuno trovasse un modo per convincere gfortran a produrre un daxpy efficiente come quello in C usando la vettorializzazione esplicita in quanto esemplifica i problemi di dover fare affidamento sul compilatore esclusivamente per l'ottimizzazione SIMD, o un caso in cui un compilatore Fortran supera la sua controparte C.


Un problema di temporizzazione è che se il tuo processore fa la modalità stepping / turbo di frequenza, questi risultati potrebbero essere su tutta la mappa.
Bill Barth,

1
Il tuo daxpy_c.c sta attualmente aggiornando x con un multiplo di x e non sta toccando affatto y. Potresti risolverlo per renderlo giusto ...
Jack Poulson,

1
@JackPoulson: buona cattura, risolto e aggiornato i risultati.
Pedro

2
Inoltre, sono abbastanza certo che la differenza sia completamente dovuta allo srotolamento manuale nella versione Fortran che confonde il compilatore. Quando lo sostituisco con lo stesso semplice loop che hai inserito nella tua versione C, le prestazioni tra i due sono quasi identiche. Senza la modifica, la versione Fortran era più lenta con i compilatori Intel.
Jack Poulson,

1
@permeakra: In realtà, lo standard C99 specifica la restrictparola chiave che dice esattamente al compilatore: supporre che un array non si sovrapponga a nessun'altra struttura di dati.
Pedro,

Risposte:


37

La differenza nei tempi sembra essere dovuta allo srotolamento manuale del daxpy Fortran a passo falcato . I seguenti tempi sono su un Xeon X5650 a 2,67 GHz, usando il comando

./test 1000000 10000

Compilatori Intel 11.1

Fortran con srotolamento manuale: 8,7 sec
Fortran senza srotolamento manuale: 5,8 sec
C senza srotolamento manuale: 5,8 sec

Compilatori GNU 4.1.2

Fortran con srotolamento manuale: 8,3 sec
Fortran senza srotolamento manuale: 13,5 sec
C senza srotolamento manuale: 13,6 sec
C con attributi vettoriali: 5,8 sec

Compilatori GNU 4.4.5

Fortran con srotolamento manuale: 8,1 sec
Fortran senza srotolamento manuale: 7,4 sec
C senza srotolamento manuale: 8,5 sec
C con attributi vettoriali: 5,8 sec

conclusioni

  • Lo srotolamento manuale ha aiutato i compilatori GNU 4.1.2 Fortran su questa architettura, ma danneggia la versione più recente (4.4.5) e il compilatore Intel Fortran.
  • Il compilatore GNU 4.4.5 C è molto più competitivo con Fortran rispetto alla versione 4.2.1.
  • I intrinseci vettoriali consentono alle prestazioni GCC di corrispondere ai compilatori Intel.

È ora di testare routine più complicate come dgemv e dgemm?


Grazie per i risultati! Quale versione di gcc stavi usando e puoi essere un po 'più specifico riguardo alla CPU?
Pedro

2
Il tuo compilatore è più vecchio della tua CPU ... Puoi provare con gcc-4.5?
Pedro

1
L'ho appena provato. La versione vettoriale con GCC 4.4.5 corrisponde esattamente ai risultati di Intel 11.1.
Jack Poulson,

1
Ho appena installato gcc / gfortran versione 4.4.5 e non riesco a riprodurre le differenze senza srotolare. In effetti, nell'assemblatore generato per entrambi i casi, il ciclo più interno è identico ad eccezione dei nomi di registro utilizzati, che sono intercambiabili. Puoi rieseguire i tuoi test solo per essere sicuro?
Pedro,

4
Possiamo dire che questo tipo di risolve il vecchio dibattito "continuiamo a usare fortran perché è più performante", così che possiamo finalmente buttarlo nel cassonetto?
Stefano Borini,

16

Sto arrivando tardi a questa festa, quindi è difficile per me seguire avanti e indietro da sopra. La domanda è grande e penso che se sei interessato potrebbe essere suddiviso in pezzi più piccoli. Una cosa che mi ha interessato è stata semplicemente la performance delle tue daxpyvarianti e se Fortran è più lento di C su questo codice molto semplice.

In esecuzione sia sul mio laptop (Macbook Pro, Intel Core i7, 2,66 GHz), le prestazioni relative della tua versione C vettorizzata a mano e della versione Fortran vettorizzata a mano dipendono dal compilatore utilizzato (con le tue opzioni):

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

Quindi, sembra solo che GCC abbia migliorato nel vettorializzare il loop nel ramo 4.6 rispetto a prima.


Nel dibattito generale, penso che si possa praticamente scrivere codice veloce e ottimizzato sia in C che Fortran, quasi come nel linguaggio assembly. Sottolineerò comunque una cosa: proprio come l'assemblatore è più noioso da scrivere rispetto a C ma ti dà un controllo più preciso su ciò che viene eseguito dalla CPU, C è più di basso livello di Fortran. Pertanto, offre un maggiore controllo sui dettagli, il che può aiutare a ottimizzare, laddove la sintassi standard di Fortran (o le sue estensioni del fornitore) potrebbero non avere funzionalità. Un caso è l'uso esplicito di tipi vettoriali, un altro è la possibilità di specificare manualmente l'allineamento delle variabili, qualcosa di cui Fortran è incapace.


benvenuti a scicomp! Concordo sul fatto che le versioni del compilatore sono importanti quanto il linguaggio in questo caso. Intendevi "di" invece di "spento nell'ultima frase?
Aron Ahmadia,

9

Il modo in cui scriverei AXPY in Fortran è leggermente diverso. È la traduzione esatta della matematica.

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

Ora chiamiamo la routine sopra in un programma.

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

Ora compiliamo ed eseguiamo ...

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

Si noti che non sto usando alcun loop o alcuna direttiva esplicita di OpenMP . Ciò sarebbe possibile in C (ovvero, nessun uso di loop e auto-parallelizzazione)? Non uso C quindi non lo so.


La parallelizzazione automatica è una funzionalità dei compilatori Intel (sia Fortran che C) e non della lingua. Quindi l'equivalente in C dovrebbe anche parallelizzarsi. Solo per curiosità, come si comporta per un n = 10000 più moderato?
Pedro

3
Questo era il punto. L'autopar è più semplice in Fortran a causa del fatto che Fortran (a differenza di C) supporta operazioni di array interi come matmult, transpose ecc. Quindi l'ottimizzazione del codice è più facile per i compilatori Fortran. GFortran (che hai usato) non ha le risorse per gli sviluppatori per ottimizzare il compilatore Fortran poiché il loro obiettivo è attualmente quello di implementare lo standard Fortran 2003 anziché l'ottimizzazione.
Stali,

Uhmm ... Il compilatore Intel C / C ++ iccesegue anche la parallelizzazione automatica. Ho aggiunto un file icctest.cad altre fonti. Puoi compilarlo con le stesse opzioni che hai usato sopra, eseguirlo e segnalare i tempi? Ho dovuto aggiungere un'istruzione printf al mio codice per evitare che gcc ottimizzasse tutto. Questo è solo un trucco rapido e spero che sia privo di bug!
Pedro

Ho scaricato gli ultimi compilatori icc / ifort e ho fatto i test da solo. La domanda è stata aggiornata per includere questi nuovi risultati, ovvero che l'autovectorization di Intel funziona sia in Fortran che in C.
Pedro,

1
Grazie. Sì, ho notato che c'è poca differenza forse perché i loop sono semplici e le operazioni sono BLAS di livello 1. Ma, come ho detto prima, grazie alla capacità di Fortran di eseguire operazioni su array completi e l'uso di parole chiave come PURE / ELEMENTAL, c'è più spazio per l'ottimizzazione del compilatore. Il modo in cui i compilatori utilizzano queste informazioni e ciò che realmente fa è una cosa diversa. Puoi anche provare matmul se vuoi bpaste.net/show/23035
stali,

6

Penso che non sia interessante solo il modo in cui un compilatore ottimizza il codice per l'hardware moderno. Soprattutto tra GNU C e GNU Fortran la generazione del codice può essere molto diversa.

Quindi consideriamo un altro esempio per mostrare le differenze tra loro.

Usando numeri complessi, il compilatore GNU C produce un grande overhead per operazioni aritmetiche quasi molto basilari su un numero complesso. Il compilatore Fortran fornisce un codice molto migliore. Diamo un'occhiata al seguente piccolo esempio in Fortran:

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

dà (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)

Che sono 39 byte di codice macchina. Quando consideriamo lo stesso in C

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

e dai un'occhiata all'output (fatto allo stesso modo come sopra), otteniamo:

  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)

Che sono anche 39 byte di codice macchina, ma il passo di funzione 57 fa riferimento, fa la parte corretta del lavoro ed esegue l'operazione desiderata. Quindi abbiamo un codice macchina a 27 byte per eseguire l'operazione multipla. La funzione dietro è muldc3 fornita da libgcc_s.soe ha un footprint di 1375 byte nel codice macchina. Questo rallenta drasticamente il codice e fornisce un output interessante quando si utilizza un profiler.

Quando implementiamo gli esempi BLAS sopra riportati zaxpyed eseguiamo lo stesso test, il compilatore Fortran dovrebbe fornire risultati migliori rispetto al compilatore C.

(Ho usato GCC 4.4.3 per questo esperimento, ma ho notato questo comportamento rilasciato da un altro GCC.)

Quindi secondo me non pensiamo solo alla parallelizzazione e alla vettorializzazione quando pensiamo a quale sia il miglior compilatore, ma dobbiamo anche guardare come le cose di base vengono tradotte nel codice assembler. Se questa traduzione fornisce un codice errato, l'ottimizzazione può usare queste cose solo come input.


1
Ho appena preparato un esempio lungo le linee del tuo codice complex.ce l'ho aggiunto al codice online. Ho dovuto aggiungere tutti gli input / output per assicurarmi che nulla fosse ottimizzato. Ricevo una chiamata solo __muldc3se non lo uso -ffast-math. Con -O2 -ffast-mathottengo 9 linee di assemblatore inline. Puoi confermare questo?
Pedro,

Ho trovato una causa più specifica per la differenza nell'assemblatore generato e l'ho aggiunto alla mia domanda sopra.
Pedro,

L'uso di -O2 porta il compilatore a calcolare tutto ciò che è possibile in fase di esecuzione, ecco perché a volte tali costrutti vengono persi. L'opzione -ffast-math non deve essere utilizzata nel calcolo scientifico quando si desidera fare affidamento sugli output.
MK aka Grisu,

1
Bene, con quell'argomento (no -ffast-math) non dovresti usare Fortran per i tuoi calcoli con valori complessi. Come descrivo nell'aggiornamento alla mia domanda, -ffast-matho, più in generale, -fcx-limited-rangeimpone a gcc di utilizzare gli stessi calcoli a intervallo limitato non IEEE come standard in Fortran. Quindi, se vuoi l'intera gamma di valori complessi e Infs e NaN corretti, non dovresti usare Fortran ...
Pedro

2
@Pedro: se vuoi che GCC si comporti come GFortran wrt. moltiplicazione e divisione complesse, dovresti usare le regole -fcx-fortran.
janneb

4

gente,

Ho trovato questa discussione molto interessante, ma sono rimasto sorpreso nel vedere che riordinare i loop nell'esempio di Matmul ha cambiato il quadro. Non ho un compilatore Intel disponibile sulla mia macchina attuale, quindi sto usando gfortran, ma una riscrittura dei loop in mm_test.f90 per

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)  

ha cambiato l'intero risultato per la mia macchina.

I risultati di temporizzazione della versione precedente erano:

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

mentre con i tripli anelli riorganizzati come sopra yeilded:

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

Questo è gcc / gfortran 4.7.2 20121109 su una CPU Intel (R) Core (TM) i7-2600K @ 3.40GHz

I flag del compilatore utilizzati erano quelli del Makefile che ho ricevuto qui ...


3
Non è sorprendente, poiché l'archiviazione della matrice in memoria favorisce un ordine, ovvero, se le righe vengono archiviate in modo contiguo, è meglio eseguire il ciclo più interno delle righe, poiché da allora è possibile caricare ciascuna riga una volta nella memoria locale veloce rispetto al caricamento ripetuto (una porzione di ) per accedere a un singolo elemento. Vedi stackoverflow.com/questions/7395556 .
Christian Clason,

Immagino di essere sorpreso che il "matmul intrinseco" non sarebbe stato codificato per fare le cose in questo modo. È sostanzialmente più veloce con il triple do ordinato nel secondo modo. Sembra essere in questo set di compilatori, dato che le versioni precedenti di gfortran che ho potuto ottenere erano più "piatte" nei loro tempi - non importava come facevi il mult - ci sono voluti quasi nello stesso tempo.
Schatzi,

-2

Non sono le lingue a rendere il codice più veloce, anche se aiutano. Sono il compilatore, la CPU e il sistema operativo a rendere i codici più veloci. Confrontare le lingue è solo un termine improprio, inutile e insignificante. Non ha alcun senso perché stai confrontando due variabili: la lingua e il compilatore. Se un codice viene eseguito più velocemente, non sai quanto sia la lingua o quanto sia il compilatore. Non capisco perché la comunità informatica non capisca questo :-(

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.