3

私は 2 ビット配列を必要としています。メモリの節約にはまったく関心がありませんが、キャッシュ ミスを最小限に抑え、キャッシュ効率を最大化することに関心があります。bool の配列を使用すると、4 倍のメモリが使用されます。つまり、キャッシュ内の使用可能なデータのチャンクごとに、使用されない 3 つのチャンクが存在することになります。したがって、技術的には、ビットフィールドを使用すると、キャッシュの一貫性が 3 倍向上します。

計画は、バイトの配列として実装し、4 つの等しいビットフィールドに分割し、div 関数を使用して整数の商と剰余を、おそらく 1 つのクロックで取得し、それらを使用して右のインデックスと右のインデックスにアクセスすることです。ビットフィールド。

必要な配列の長さは約 10000 要素なので、非常に高密度のパック データが作成されます。2 つの実際のビットを使用すると、配列全体を L1 キャッシュに収めることができますが、バイト配列を使用すると、これは不可能になります。

私の質問は、パフォーマンス指向のタスクでこれが良いアイデアであるかどうかを誰かが教えてくれるかどうかです.2ビット配列を実装する価値があるかどうかはわかりますか? 確かに、知るための最良の方法はプロファイリングですが、事前の情報は有用であり、高く評価されます。

4

2 に答える 2

5

10000要素の場合、最新のプロセッサでは、バイト(10KB)としてメモリにうまく収まるはずなので、キャッシュがはるかに小さい非常に小さなマイクロプロセッサで実行する場合を除いて、あまり心配する必要はありません。最新のCPUが持つ典型的な16-32KBのL1キャッシュよりも。

もちろん、これがパフォーマンスの観点からコードの重要な部分であると考える場合は、さまざまなソリューションでパフォーマンスをテストすることをお勧めします[最適化を開始する前にすでに行ったプロファイリングから測定してください]。 。

于 2013-01-20T18:28:28.497 に答える
2

これがパフォーマンスの向上につながるかどうかは、私には明らかではありません。各フィールドへのアクセスには複数の命令が必要であり ( (data[i / 4] >> 2 * (i % 4)) & 0x03)、最新のプロセッサの多くは、エントリごとに 1 バイトで配列全体を保持する L3​​ キャッシュを備えています。実行時間の追加コストがキャッシングの差よりも大きいか小さいかはわかりません。正確に知るにはプロファイルする必要があります。

一度に 1 バイト (または 1 ワード) ずつ動作するようにアルゴリズムを編成できれば、アクセスのコストは大幅に削減される可能性があります。配列全体を反復します。たとえば、次のようになります。

for ( int i = 0; i < 10000; i += 4 ) {
    unsigned char w1 = data[ i / 4 ];
    for ( int j = 0; j < 4; ++ j ) {
        unsigned char w2 = w1 & 0x03;
        //  w2 is entry i + j...
        w1 >>= 2;
    }
}

大きな違いを生む可能性があります。ほとんどのコンパイラはレジスタに保持できるためw1w2メモリ アクセスは 1/4 しかありません。unsigned int`でパッキングすると、おそらくさらに高速になります。

于 2013-01-20T18:41:39.487 に答える