7

ファイルを解析するプログラムを書いています。これは、文字ごとに解析して処理するメイン ループで構成されます。メインループは次のとおりです。

char c;
char * ptr;

for( size_t i = 0; i < size ; ++i )
{
    ptr = ( static_cast<char*>(sentenceMap) + i );
    c = *ptr;

    __builtin_prefetch( ptr + i + 1 );

   // some treatment on ptr and c   
}

ご覧のとおりbuiltin_prefetch、ループの次の繰り返しをキャッシュに入れることを期待して、命令を追加しました。さまざまな値を試してみました : ptr+i+1, ptr+i+2,ptr+i+10しかし、何も変わらないようです。

パフォーマンスを測定するために、valgrind のツール cachegrind を使用します。キャッシュ ミスの数がわかります。行c = *ptrで、 が設定されていない場合、cachegrind は 632,378 DLmr (L3 キャッシュ ミス) を記録し__builtin_prefetchます。ただし、奇妙なのは、設定したパラメーターに関係なく、この値が変化しないこと__builtin_prefetchです。

それに対する説明はありますか?

4

3 に答える 3

12

それは、ハードウェアが何年も先を行っているからです。:)

単純なパターンを認識してプリフェッチを行うように設計されたハードウェア プリフェッチャーがあります。この場合、単純なシーケンシャル アクセス パターンがあり、ハードウェア プリフェッチャーにとっては些細なことではありません。

手動プリフェッチは、ハードウェアが予測できないアクセス パターンがある場合にのみ役立ちます。

そのような例の 1 つを次に示します。

于 2012-09-19T04:36:54.930 に答える
3

まず最初に、キャッシュが処理する最小単位が呼び出されcache line、キャッシュ ラインは、たとえば 64 バイトの長さにすることができますが、1 バイトほど小さくすることはできません。したがって、プリフェッチを要求するときは、現在の関心のある場所よりも多くのことを要求する必要があります。キャッシュ ラインのサイズを知る必要があるため、同じキャッシュ ラインにあるアドレスを要求するべきではありません。また、プリフェッチを何度も呼び出さないようにする必要があります。これは、使用されるキャッシュ ラインがすぐに削除され、命令が実行されるとパフォーマンス ヒットが発生する可能性があるためです。

最新のアーキテクチャにはハードウェア プリフェッチャーの概念もあり、アクセス パターンに応じて事前にデータをプリフェッチできます。これは、ほとんどの場合、単純なプリフェッチと同じくらい良いデータ アクセス時間を作成する必要があります。今日では、ソフトウェアのプリフェッチは、コードをランダムに拡散するのではなく、データをプリフェッチするための明確な場所を見つけることができる場合にのみ役立ちます。たとえば、データの処理を開始する前ですが、プリフェッチを呼び出してすぐにデータにアクセスするだけでは役に立ちません。データにアクセスする前に、これを十分早い段階で行い、他のセットアップ作業を行う必要があります。

このようなトピックに興味がある人は、The Software Optimization Cookbookを読むことをお勧めします。私は一般的に ARM アーキテクチャを扱っていますが、この本は非常に貴重であることがわかりました。この質問に関連する抜粋もオンラインで入手できます。#1#2を参照してください。

于 2012-09-19T06:19:41.920 に答える
1

正しい答えは: プリフェッチはキャッシュ ミスの数を変更することはできず、それらをより早く発生させるだけです :)

于 2014-02-07T16:44:52.207 に答える