I compilatori Fortran generano realmente un codice più veloce rispetto ai compilatori C?

17

Quando studiavo all'università ho sentito spesso l'idea che i compilatori Fortran producevano un codice più veloce rispetto ai compilatori C per un programma equivalente.

Il ragionamento chiave è andato così: un compilatore Fortran emette in media 1,1 istruzioni per processore per riga di codice, mentre un compilatore C emette in media 1,6 istruzioni per processore per riga di codice - Non ricordo i numeri esatti, ma l'idea era che i compilatori C emettessero notevolmente più codice macchina e quindi producessero programmi più lenti.

Quanto è valido tale confronto? Possiamo dire che i compilatori Fortran producono programmi più veloci dei compilatori C o viceversa e perché esiste questa differenza?

    
posta sharptooth 21.03.2011 - 09:29
fonte

6 risposte

36

IIRC uno dei motivi principali per cui Fortran si dice che sia più veloce è l'assenza di alias del puntatore , quindi possono utilizzare le ottimizzazioni che i compilatori C non possono utilizzare:

In FORTRAN, function arguments may not alias each other, and the compiler assumes they do not. This enables excellent optimization, and is one major reason for FORTRAN's reputation as a fast language. (Note that aliasing may still occur within a FORTRAN function. For instance, if A is an array and i and j are indices which happen to have the same value, then A[i] and A[j] are two different names for the same memory location. Fortunately, since the base array must have the same name, index analysis can be done to determine cases where A[i] and A[j] cannot alias.)

Ma sono d'accordo con gli altri qui: il confronto del numero medio di istruzioni assembler generate per una riga di codice non ha senso. Ad esempio un moderno core x86 può eseguire due istruzioni in parallelo se non accedono agli stessi registri. Quindi (in teoria) puoi ottenere un aumento delle prestazioni del 100% per lo stesso insieme sulle istruzioni semplicemente riordinandole . I buoni compilatori generano spesso più istruzioni di assemblaggio per ottenere codice più veloce (think loop srotolamento, inlining). Il numero totale di istruzioni assembler dice molto poco sulle prestazioni di un pezzo di codice.

    
risposta data 21.03.2011 - 10:22
fonte
8

Confronto completamente non valido.

In primo luogo, come @ sottolinea Péter Török, devi prima confrontare il numero di righe in programmi equivalenti da Fortran e C per fare in modo che sia anche un confronto valido sul numero di righe prodotte.

Secondo, meno linee di codice non sempre equivalgono ai programmi più veloci . Non tutte le istruzioni della macchina richiedono lo stesso numero di cicli da eseguire , ma hai anche altri problemi come accesso alla memoria , memorizzazione nella cache , ecc.

Inoltre, le esecuzioni di codice lunghe possono essere più veloci poiché comportano un numero inferiore di righe di esecuzione (ad esempio, Conteggio righe! = Conteggio righe eseguite ).

    
risposta data 21.03.2011 - 09:47
fonte
5

Dan è corretto, i programmi più lunghi non significano programmi più lenti. Dipende molto da quello che stanno facendo.

Non sono un esperto di Fortran, lo so un po '. Confrontandoli, direi che sarebbe ben scritto C farebbe molto meglio nelle prestazioni con strutture dati e funzionalità più complesse di Fortran. Qualcuno (per favore) correggimi se sbaglio qui, ma penso che Fortran sia un po 'a un livello inferiore rispetto a C. Se è così, sono sicuro che alcuni problemi sarebbero usciti più velocemente su Fortran.

Un'altra cosa, a prima vista ho pensato che stavi chiedendo se i compilatori fossero più veloci. In realtà penso che Fortran compilerà in genere più velocemente per quantità simili di codice, ma il programma risultante e il modo in cui viene eseguito sarebbero una storia diversa. È più semplice da analizzare.

    
risposta data 21.03.2011 - 09:57
fonte
4

Penso che parte di esso sia che i compilatori FORTRAN sono progettati per eseguire alcuni tipi di matematica molto velocemente. Questo è il motivo per cui le persone usano FORTRAN, per fare calcoli il più velocemente possibile

    
risposta data 21.03.2011 - 09:50
fonte
4

La frase potrebbe essere stata vera nei vecchi tempi (circa alla fine degli anni '70) quando C era ancora agli inizi e Fortran era supportato da tutti i principali produttori e altamente ottimizzato. I primi Fortrans erano basati sull'architettura IBM, cose così semplici come l'aritmetica se sarebbe stata certamente una dichiarazione per ogni istruzione di assemblaggio. Questo è vero per le macchine più datate come Data General e Prime, che avevano salti a 3 vie. Questo non funziona con insiemi di istruzioni moderni che non hanno un salto a 3 vie.

Le linee di codice non equivalgono a dichiarazioni di codice. Le versioni precedenti di Fortran consentivano solo un'istruzione per riga. Versioni successive di Fortran possono prendere più istruzioni per riga. C può avere più istruzioni per riga. Nei compilatori di produzione più veloci come Intel IVF (precedentemente CVF, MS Powerstation) e Intel C, non c'è davvero alcuna differenza tra i due. Questi compilatori sono altamente ottimizzati.

    
risposta data 17.04.2012 - 08:04
fonte
4

FORTRAN vecchio stile richiedeva che un programmatore che voleva rendere parte di un array disponibile per una funzione necessitasse di passare un riferimento all'intero array, insieme a uno o più valori interi che specificano il pedice iniziale e l'indice finale o numero di articoli. C rende possibile semplificare questo passaggio al puntatore all'inizio di la parte di interesse insieme al numero di elementi. In termini diretti, ciò renderebbe le cose più veloci (passando due cose anziché tre). Indirettamente, tuttavia, potrebbe finire per rallentare le cose limitando i tipi di ottimizzazione che un compilatore può eseguire.

Considera la funzione:

void diff(float dest[], float src1[], float src2[], int n)
{
  for (int i=0; i<n; i++)
    dest[i] = src1[i] - src2[i];
}

se un compilatore sapeva che ognuno dei puntatori avrebbe identificato l'inizio di un array, potrebbe generare un codice che agisca su elementi del array in parallelo, o in qualsiasi ordine, poiché per qualsiasi x! = y, operazioni attive dest [x] non influenzerà src1 [y] né src2 [y]. Ad esempio, su alcuni sistemi un compilatore può trarre beneficio dalla generazione di codice equivalente a:

void dif(float dest[], float src1[], float src2[], int n)
{
  int i=0;
  float t1a,t1b,t2a,t2b,tsa,tsb;
  if (n > 2)
  {
    n-=4;
    t1a = src1[n+3]; t1b = src2[n+3]; t1b=src2[n+2]; t2b = src2[n+2];
    do
    {
      tsa = t1a-t2a;
      t1a = src1[n+1]; t2a = src2[n+1]; 
      tsb = t2b-t2b;
      dest[n+3] = tsa;
      t1b = src1[n]; t2b = src2[n]; 
      n-=2;
      dest[n+4] = tsb;
    } while(n >= 0);
    ... add some extra code to handle cleanup
  }
  else
    ... add some extra code to handle small values of n
}

Si noti che ogni operazione che carica o calcola un valore ha almeno un'altra operazione tra questa e l'operazione successiva che utilizza quel valore. Alcuni processori possono sovrapporsi all'elaborazione di diverse operazioni quando tali condizioni sono soddisfatte, migliorando così le prestazioni. Si noti, tuttavia, che poiché un compilatore C non ha modo di sapere che il codice non verrà passato puntatori a regioni parzialmente -overlapping di un array comune, un compilatore C non può effettuare la trasformazione di cui sopra . I compilatori FORTRAN dati un codice equivalente, tuttavia, potevano e facevano una tale trasformazione.

Mentre un programmatore C poteva tentare di ottenere prestazioni comparabili scrivendo esplicitamente il codice che srotolava il ciclo e sovrapponeva le operazioni dei passaggi adiacenti, tale codice poteva facilmente degradare le prestazioni se utilizzava così tante variabili automatiche che un compilatore doveva "spargere" "loro alla memoria. Un ottimizzatore del compilatore FORTRAN probabilmente conoscerebbe più di un programmatore su quali forme di interleaving offrirebbero prestazioni ottimali in un dato scenario e tali decisioni sono spesso lasciate a tali compilatori. Mentre C99 ha tentato di migliorare un po 'la situazione di C aggiungendo un qualificatore restrict , potrebbe essere usato qui solo se dest[] era un array separato da src1[] e src2[] , o se il programmatore ha aggiunto versioni separate del ciclo per gestire i casi in cui tutto dest era disgiunto da src1 e src2 , dove src1[] e dest erano uguali e src2 era disgiunto, dove src2[] e dest[] erano uguali e src1 era disgiunto e dove tutti e tre gli array erano uguali. FORTRAN, al contrario, potrebbe gestire tutti e quattro i casi senza difficoltà utilizzando lo stesso codice sorgente e lo stesso codice macchina.

    
risposta data 21.04.2017 - 19:06
fonte

Leggi altre domande sui tag