2016-03-30 15 views
3

ich kämpfen, ich zu verstehen, warum dieser Code ausgeführt wird mit rasantem Tempo mit Intel-Compiler 12 und verlangsamt wirklich unten mit Intel-Compiler 16Intel compilator für Schleifengeschwindigkeit c

#include <stdlib.h> 
#include <time.h> 
int main(int argc, char *argv[]) 
{ 
    int i,t; 
    int n=10000000; 
    int T=1000; 
    time_t t1,t2; 

    // double A[n],B[n],C[n]; 
    double *A = (double*) malloc (sizeof(double)*n); 
    double *B = (double*) malloc (sizeof(double)*n); 
    double *C = (double*) malloc (sizeof(double)*n); 



    for (i=0;i<n;i++) 
    { 
     A[i]=1.0; 
     B[i]=2.0; 
    } 
    t1=clock(); 

    for (t=0;t<T;t++) 
     for (i=0;i<n;i++) 
      C[i]=A[i]*B[i]; 

    t2=clock(); 
    double sum=0.0; 
    for (i=0;i<n;i++) sum += C[i]; 
    printf("sum %f\n",sum); 
    printf("time %f\n",(double)(t2-t1)/CLOCKS_PER_SEC); 
} 

  • Intel Compiler 12 : Dauert 0,1 Sekunden, um auf sandiger Brücke zu laufen; Intel Compiler 16: dauert 25 Sekunden lang auf Sandbrücke laufen

Make-Datei: ICC -O2 -o Array Array.c

+1

Nicht verwandt: Werfen Sie nicht das Ergebnis von 'malloc' & Freunde in C! – Olaf

+0

Vielleicht machen die 'double' 'volatile'? –

+2

Haben Sie "-O3" anstelle von "-O2" probiert? –

Antwort

5

Wahrscheinlich eine der Compiler aggressiv die gesamte belastende verschachtelten Schleife optimiert entfernt. Es scheint wahrscheinlich, dass Ihre optimierten Code tatsächlich endet als:

t1=clock(); 
t2=clock(); 
double sum=0.0; 
for (i=0;i<n;i++) sum += A[i]*B[i]; 

Es ist völlig in Ordnung für den Compiler solche Optimierungen zu tun. Sie können Optimierungen blockieren, indem Sie die Loop-Iteratoren volatile ausführen.

Stellen Sie sicher, dass auf beiden Compilern die gleiche Optimierungsebene aktiviert ist.

+3

Wenn wir nicht von einer Tatsache sprechen, 'A' und' B' sind Konstanten für alle '[i]' ... die Schleifen können komplett verschwinden. –

+1

@EugeneSh. Ja, das ist ein vereinfachtes Beispiel. Es wird noch mehr Optimierungen im realen Programm geben, besonders bei "-O3". – Lundin

+0

Ja. Das muss es sein. Wenn Sie volatile hinzufügen, wird es mit allen Compilern kompiliert –

2

Die zwei verschachtelten Schleifen sind vectorisable die Compiler bereitgestellt ist sicher, dass die drei Bereiche des Speichers spitz durch A, B und C nicht alias. Insbesondere können die Werte, die in C gespeichert sind, nie wieder durch A und B gelesen werden - was eine Gefahr wäre, wenn die Iterationen der Schleife parallel ausgeführt würden, mit einer anderen Lade- und Speicherreihenfolge als im Code. Im allgemeinen Fall kann der Compiler dies nicht von Zeigern ableiten, die von einem Funktionsaufruf zurückgegeben werden, obwohl es legitim sein könnte, mehr über die Semantik von Standardbibliotheksfunktionen wie malloc() als die Funktionssignatur zu erfahren allein würde schließen.

Es ist möglich, dass die Unterschiede in der Strenge der Aliasing-Regeln zwischen Compiler-Versionen - oder möglicherweise von anderen Standardoptionsschaltern - liegen.

Das Hinzufügen des Qualifikationsmerkmals restrict zu den Zeigerdeklarationen teilt dem Compiler mit, dass es annehmen kann, dass das Aliasing nicht durch die Verwendung des Zeigers erfolgen kann und dass die Aufgabe auf dem Programmierer liegt, dies zu garantieren.

double * restrict A = malloc (sizeof(double)*n); 
double * restrict B = malloc (sizeof(double)*n); 
double * restrict C = malloc (sizeof(double)*n); 
Verwandte Themen