2
void foo(Node* p[], int size){

    _uint64 arr_of_values[_MAX_THREADS];


    for (int i=0 ; i < size ; i++ ){
         arr_of_values[i] = p[i]->....;

         // much code here 
         // 
      }
 }

void foo(Node* p[], int size){

    _uint64 arr_of_values[_MAX_THREADS];

    Node* p_end = p[size];
    for ( ; p != p_end ; ){            
         arr_of_values[i] = (*p)->.....;
         p++;


         // much code here 
         // 
     }

}

私が求めていることを示すために、この関数を作成しました:

キャッシュ効率の観点からは、どちらがより効率的ですか: p[i] を使用するか、*p++ を使用しますか?

(残りのコードでは決して p[ix] を使用しませんが、次の計算では p[i] または *p を使用する場合があります)

4

2 に答える 2

2

最も重要なのは、での誤った共有を避けることarr_of_valuesです。各スレッドは独自のスロットに書き込みますが、(CPU に応じて) 8 つまたは 16 のスロットがキャッシュ ラインを共有するため、大規模な偽共有の問題が発生します。スロット間にパディングを追加して、キャッシュを各スレッドのスロットに揃えるか、スタックに蓄積して最後に 1 回だけ書き込みます。

void foo(Node* p[], int size){

    _uint64 arr_of_values[_MAX_THREADS];

    Node* p_end = p[size];
    for ( ; p != p_end ; ){            
         temp = .....;
         p++;
         // much code here 
         // 
     }  
     arr_of_values[i] = temp;
}

ポインタによるアクセスまたはインデックスによるアクセスの問題は、今日のコンパイラには関係ありません。

あなたの次の行動は次のとおりです。ソフトウェア最適化クックブックのコピーを入手してください。それを読んで。測定。推測値ではなく、測定されたホットスポットを修正します。

于 2012-06-27T13:50:50.067 に答える
1

キャッシュの観点からの問題は、要素にアクセスする方法ではありません。この場合、ポインタまたは配列インデックスを使用することは同等です。

ところでノード*p[]はポインタの配列です。したがって、Nodeオブジェクトを離れたメモリ領域に割り当てることができた可能性があります。(たとえば、いくつかのptr = new Node()を使用します)。次の場合に最高のキャッシュパフォーマンスが得られます。

  1. ノードは連続してメモリに保存されます
  2. ノードサイズはキャッシュサイズを超えません。
于 2012-06-27T13:59:52.497 に答える