-1

次のコードを考えると:

for (int i=0; i<n; i++)
{
  counter += myArray[i];
}

そして、ループ展開バージョン:

for (int i=0; i<n; i+=4)
{
  counter1 += myArray[i+0];
  counter2 += myArray[i+1];
  counter3 += myArray[i+2];
  counter4 += myArray[i+3];
}

total = counter1+ counter2 + counter3+ counter4;
  1. 最初のバージョンでキャッシュ ミスが発生するのはなぜですか?
  2. 2 番目のバージョンは実際に 1 番目よりもパフォーマンスが優れていますか? なぜ ?

よろしく

4

1 に答える 1

4

最初のバージョンでキャッシュ ミスが発生するのはなぜですか?

Oli がコメントで指摘しているように。この質問には根拠がありません。データがすでにキャッシュにある場合、キャッシュ ミスは発生しません。

それはさておき、2 つの例の間でメモリ アクセスに違いはありません。そのため、それらの間のパフォーマンスの違いの要因にはなりません。

2 番目のバージョンは実際に 1 番目よりもパフォーマンスが優れていますか? なぜ ?

通常は、実際に測定することになります。しかし、この特定の例では、より高速になる可能性が高いと言えます。キャッシュ アクセスが改善されたからではなく、ループ展開が行われたからです。

あなたが行っている最適化は「ノード分割」と呼ばれcounter、依存関係の連鎖を断ち切る目的で変数を分離します。

ただし、この場合、単純なリダクション操作を行っています。最新のコンパイラの多くは、このパターンを認識して、このノード分割を行うことができます。

それで、それはより速いですか?最も可能性が高い。ただし、コンパイラがそれを行うかどうかを確認する必要があります。


記録のために: Visual Studio 2010 でこれをテストしました。この最適化を実行できないこと
に非常に驚いています。

; 129  : 
; 130  :     int counter = 0;
; 131  : 
; 132  :     for (int i=0; i<n; i++)
    mov ecx, DWORD PTR n$[rsp]
    xor edx, edx
    test    ecx, ecx
    jle SHORT $LN1@main
$LL3@main:

; 133  :     {
; 134  :         counter += myArray[i];

    add edx, DWORD PTR [rax]
    add rax, 4
    dec rcx
    jne SHORT $LL3@main
$LN1@main:

; 135  :     }

Visual Studio 2010 は、この (簡単な) 例では「ノード分割」を実行できないようです...

于 2012-04-08T19:46:23.783 に答える