7

粒子相互作用のシミュレーションに取り組んでいるときに、効率的な最近傍セル検索を提供すると見なされているMorton オーダー (Z オーダー) ( Wikipedia リンク)のグリッド インデックス付けに出くわしました。私が読んだ主な理由は、メモリ内の空間的に近いセルのほぼ連続した順序付けです。

最初の実装の途中であるため、特に基本的な均一グリッドと比較して、最近傍のアルゴリズムを効率的に実装する方法について頭を悩ませることはできません。

  1. セル (x,y) が与えられた場合、8 つの隣接セル インデックスを取得し、それぞれの z インデックスを計算するのは簡単です。これにより、要素への一定のアクセス時間が提供されますが、z-index を計算するか、事前定義されたテーブルで検索する必要があります (軸ごとに分離し、OR を計算します)。どうすればこれがより効率的になるでしょうか? 配列 A の要素に A[0] -> A 1 -> A[3] -> A[4] -> ... という順序でアクセスすると、A[1023 の順序よりも効率的です。 ] -> A[12] -> A[456] -> A[56] -> ...?

  2. Z オーダーで最近傍を見つけるためのより単純なアルゴリズムが存在することを期待していました。線に沿った何か: 隣接セルの最初のセルを見つけて、反復します。しかし、これは 2^4 サイズのブロック内でのみうまく機能するため、そうではありません。ただし、2 つの問題があります。セルが境界上にない場合、ブロックの最初のセルを簡単に特定してブロック内のセルを反復処理できますが、セルが最近傍セルであるかどうかを確認する必要があります。セルが境界上にある場合は、2^5 個のセルを考慮する必要がある場合よりも悪いことになります。ここで何が欠けていますか?私が必要とすることを行う比較的単純で効率的なアルゴリズムはありますか?

ポイント 1. の質問は簡単にテストできますが、記述されたアクセス パターンが生成する基本的な命令についてはあまり詳しくなく、舞台裏で何が起こっているのかを本当に理解したいと思っています。

ヘルプ、参考文献など、事前に感謝します...


編集:
ポイント1を明確にしていただきありがとうございます!ということで、Z-orderingを使うと隣接セルのキャッシュヒット率が平均的に上がるというのは興味深いですね。キャッシュのヒット/ミス率をプロファイリングする方法はありますか?

ポイント2に関して:インデックスi = f(x1、x2、...、xd)がビットごとのインターレースなどから取得されるR ^ dの点群のモートン順序配列を構築する方法を理解していることを追加する必要があります.私が理解しようとしているのは、次の単純な ansatz よりも、最近傍を取得するためのより良い方法があるかどうかです (ここでは d=2、「疑似コード」)。

// Get the z-indices of cells adjacent to the cell containing (x, y) 
// Accessing the contents of the cells is irrelevant here
(x, y) \elem R^2    
point = (x, y)
zindex = f(x, y)     
(zx, zy) = f^(-1)(zindex)          // grid coordinates 
nc = [(zx - 1, zy - 1), (zx - 1, zy), (zx - 1, zy + 1),  // neighbor grid 
      (zx    , zy - 1),               (zx,     zy + 1),  // coordinates
      (zx + 1, zy - 1), (zx + 1, zy), (zx + 1, zy + 1)]

ni= [f(x[0], x[1]) for x in nc]    // neighbor indices
4

2 に答える 2

10

最新のマルチレベル キャッシュ ベースのコンピューター システムでは、データ要素へのアクセス時間を最適化する上で、空間的局所性が重要な要素となります。

簡単に言えば、これは、メモリ内のデータ要素にアクセスする場合、近くにあるメモリ内の別のデータ要素 (最初のアドレスに近いアドレスを持つ) にアクセスすると、他のデータ要素にアクセスするよりも数桁安くなる可能性があることを意味します。遠く。

単純に画像処理や音声処理を行ったり、各要素を同じ方法で処理するデータ構造を反復処理したりする場合のように、1 次元データが順次アクセスされる場合、メモリ内のデータ要素を順番に配置すると、空間的局所性が達成される傾向があります。つまり、要素にアクセスするためです。要素 N にアクセスした直後の N+1 では、2 つの要素をメモリ内で隣り合わせに配置する必要があります。

標準の c 配列 (および他の多くのデータ構造) には、このプロパティがあります。

Morton 順序付けのポイントは、データが1次元ではなく2次元でアクセスされるスキームをサポートすることです。つまり、要素 (x,y) にアクセスした後、(x+1,y) または (x,y+1) などにアクセスできます。

モートン順序付けは、(x,y)、(x+1,y)、および (x,y+1) がメモリ内で互いに近いことを意味します。標準の c 多次元配列では、これは必ずしも当てはまりません。たとえば、配列 myArray[10000][10000] では、(x,y) と (x,y+1) は 10000 要素離れており、空間的局所性を利用するには離れすぎています。


Morton 順序付けでは、標準の c 配列をデータのストアとして引き続き使用できますが、(x,y) がどこにあるかを計算する計算は、store[x+y*rowsize] ほど単純ではありません。

Morton 順序付けを使用してアプリケーションを実装するには、座標 (x,y) をストア内の住所に変換する方法を考える必要があります。f(x,y)つまり、のようにストアにアクセスするために使用できる関数が必要ですstore[f(x,y)]

さらに調査を行う必要があるようです - ウィキペディアのページ、特にBIGMIN関数に関するリンクをたどってください。

于 2010-11-23T20:18:38.000 に答える
4

はい、配列要素に順番にアクセスする方が確かに高速です。CPU は、メモリを RAM からキャッシュにチャンク単位でロードします。シーケンシャルにアクセスすると、CPU は次のチャンクを簡単にプリロードでき、ロード時間に気付かないでしょう。ランダムにアクセスすると、それはできません。これはキャッシュ コヒーレンシと呼ばれ、既にアクセスしたメモリに近いメモリにアクセスする方が高速であることを意味します。

あなたの例では、A[1]、A[2]、A[3]、およびA[4]をロードするときに、プロセッサはおそらくこれらのインデックスのいくつかを一度にロードし、非常に簡単にしました。さらに、A[5] にアクセスしようとすると、A[1] などを操作している間にそのチャンクをプリロードできるため、ロード時間が実質的にゼロになります。

ただし、A[1023] をロードする場合、プロセッサはそのチャンクをロードする必要があります。次に、まだロードしていない A[12] をロードする必要があるため、新しいチャンクをロードする必要があります。などなど。ただし、あなたの質問の残りの部分についてはわかりません。

于 2010-11-23T19:45:15.097 に答える