2017-03-18 71 views
-1

我注意到用C初始化一個數組的兩種不同方式在編譯O3優化後似乎導致了非常不同的運行時間。這裏是一個最小(雖然無意義)例如複製這種差異:用「靜態」初始化數組更改運行時間?

#include <stdio.h> 
#include <time.h> 

int main(void) { 
    int i, j, k; 
    int size=10000; 
    int a[size]; 
    clock_t time1 = clock(); 
    for (i=0; i<size; i++) { 
     for (j=0; j<300000; j++) { 
      for (k=0; k<700000; k++) { 
       a[i] = j+k; 
      } 
     } 
    } 
    clock_t time2 = clock(); 
    double time = (double)(time2-time1)/CLOCKS_PER_SEC*1000.0; 
    printf("%f\n", time); 
    getchar(); 
    return 0; 
} 

編譯該程序與GCC(Ubuntu的5.4.0-6ubuntu1〜16.04.4)5.4.0 20160609與接通O3優化。這個程序需要約0.02s在我的電腦上完成。

現在,將數組初始化從「int a [size];」到「static int a [10000];」並保持其他一切。再次編譯時使用相同的環境和O3優化。這一次,該程序運行約0.001s

任何人都可以解釋爲什麼有這樣的不同?謝謝!

+0

您更改爲靜態,並使用常量而不是您顯示的VLA代碼。你改變了兩件事,所以誰知道哪一件可能會有所作爲? –

+2

使用'-S'編譯並查看程序集。 – user3386109

+0

@RetiredNinja感謝您指出這一點。如果我使用「static int a [size];」 (即使用變量名而不是常數10000),那麼我得到錯誤「a'的存儲大小不是常量」。這就是爲什麼我「靜態int a [10000]」; – user3026001

回答

0

我認爲這在很大程度上取決於編譯器。我的GCC5.4在靜態存在時完全消除了循環,很可能是因爲它可以發現計算沒有副作用(「死代碼消除」)。出於某種原因,當VLA出現時,它就不能這麼做(這是缺少的優化)。

作爲一個方面說明,要可靠地測量性能,您需要防止編譯器優化太多。在你的情況下,我建議分開陣列創建和計算,例如像

void __attribute__((noinline, noclone)) benchmark(int *a, int size) { 
    for (i=0; i<size; i++) 
    for (j=0; j<300000; j++) 
    for (k=0; k<700000; k++) 
    a[i] = j+k; 
} 

int main(void) { 
    int i, j, k; 
    int size=10000; 
    int a[size]; 
    clock_t time1 = clock(); 
    benchmark(a, size); 
    clock_t time2 = clock(); 
    double time = (double)(time2-time1)/CLOCKS_PER_SEC*1000.0; 
    printf("%f\n", time); 
    getchar(); 
    return 0; 
} 
+0

謝謝,這很有幫助! – user3026001