2016-03-30 106 views
3

我掙扎理解爲什麼這個代碼與英特爾編譯器12起泡的速度運行,而真正與英特爾編譯器16英特爾compilator for循環速度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); 
} 

  • 英特爾編譯器12減慢:在沙質橋上跑0.1秒;英特爾 編譯器16:取25秒在沙質橋運行

生成文件: ICC -O2 -o陣列array.c

+1

不相關:不要在C中投放'malloc'和好友的結果! – Olaf

+0

也許會使'double's'volatile'? –

+2

您是否嘗試過使用'-O3'而不是'-O2'? –

回答

5

可能的是,編譯器中的一個積極優化去掉一個繁重的嵌套循環。看起來您的優化代碼似乎很可能實際上結束爲:

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

編譯器完成此類優化是非常好的。您可以通過使循環迭代器volatile來阻止優化。

確保您在兩個編譯器上啓用了相同級別的優化。

+3

沒有提到事實'A'和'B'是所有'[i]'的常量......循環可以完全消失。 –

+1

@EugeneSh。是的,這是一個簡單的例子。真正的程序會有更多的優化,尤其是在'-O3'。 – Lundin

+0

是的。這一定是它。添加volatile會使其運行相同,並與所有編譯器一起編譯 –

2

這兩個嵌套循環是vectorisable,只要編譯器確定ABC所指向的三個內存區域不是別名。具體而言,通過C存儲的值永遠不能通過AB重新讀取 - 如果循環的迭代並行運行,並且載入和存儲順序不同於代碼中的暗示順序,則這將是一種危險。

在一般情況下,編譯器將不能從函數調用返回的指針中推斷出它,儘管它可以合法地知道更多關於標準庫函數的語義,比如函數簽名的malloc()獨自會推斷。

您看到的差異可能是由於編譯器版本之間的別名規則的嚴格性 - 或者可能來自不同的默認選項開關而引起的。

restrict限定符添加到指針聲明中會告訴編譯器,它可以假定通過使用指針不會發生別名,並且負責保證這一點。

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