2017-03-18 7 views
-1

Cで配列を初期化する2つの異なる方法は、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; 
} 

オンO3の最適化とのgcc(Ubuntuの5.4.0-6ubuntu1〜16.04.4)5.4.0 20160609でこのプログラムをコンパイルします。このプログラムは約0.02sで終了します。

ここで、配列の初期化を「int a [size];」に変更します。 「静的int a [10000];」に変更します。それ以外のものはすべて同じにしておきます。再び同じ環境とO3の最適化でコンパイルしてください。今回は約0.001sのプログラムが実行されます。

このような違いがある理由は誰でも説明できますか?ありがとう!

+0

あなたが示したVLAコードではなく、静的に変更して定数を使用しました。あなたは2つのものを変更したので、どちらが違いを生むのか分かりますか? –

+2

'-S'でコンパイルし、アセンブリを見ます。 – user3386109

+0

@RetiredNinjaこれを指摘してくれてありがとう。私が "static int a [size];" (すなわち、定数10000の代わりに変数名を使用すると)「aの記憶容量は一定ではありません」というエラーが表示されます。だからこそ私は "static int a [10000];" – user3026001

答えて

0

これはコンパイラに大きく依存すると思います。私のGCC 5.4は静的が存在するときにループを完全に削除します。これは、計算に副作用がない(「デッドコードの消去」)ということが分かるからです。何らかの理由で、VLAが存在するときには失敗します(最適化が欠けている)。

パフォーマンスを確実に測定するためには、コンパイラが最適化しすぎないようにする必要があります。あなたの場合、配列の作成と計算を分けておくことをお勧めします。 like

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

関連する問題