(方法)メモリの断片化を考慮していますか?


8

私は有限要素理論の例を使用しますが、大規模なデータ構造を維持し、それを連続的に拡張する人なら誰でも同じようなものを見つけるでしょう。

ポイントと三角形の非構造化メッシュがあり、ポイントが座標(たとえばと)で与えられ、三角形がそれぞれ3つのポイントインデックス(たとえば、jk)で構成されているとします。バツyjk

FEMで一般的なように、メッシュは連続的に細分割されます。グローバルな通常の絞り込みに頼ると、三角形の数は、絞り込みが繰り返されるたびに4倍になります4。これがどのように行われるかに応じて、メモリレイアウトの開発方法は異なります。

メッシュが1〜300のメモリセルを占めているとします。

例1:

新しいメッシュのセル301から1501にスペースを割り当て、そこにリファインされたメッシュのデータを入力して、古いメッシュを忘れます。次のリファインされたメッシュはセル1501〜6300に配置され、次のメッシュは6301〜21500に配置されます。現在のメッシュの場所はメモリ内で「右」に移動しますが、巨大なパッチは使用されません。時期尚早にメモリ不足になる場合があります。

上記の例では、1つのリファインステップの妨げになるだけであることに気づくかもしれません。これは、断片化がなくても、後でリファインメントの合計メモリが不足するためです。頂点配列も考慮されるため、問題はさらに深刻になる可能性があります。

どうすればこれを回避できますか?

例2:

三角形の配列をセル1..1200に再割り当てします。セル1201から2400に新しいメッシュを作成します。その作業コピーの内容をセル1..1200にコピーし、作業コピーを忘れます。同様に繰り返します。

作業コピーが必要なため、まだメモリが不足しています。これはどう:

例3:

三角形の配列をセル1..1500に再割り当てします。古いメッシュを1201 .. 1500にコピーします。セル1..1200に新しいメッシュを作成します。次に、古いメッシュのコピーを忘れます。

これらのスケールではグローバルメッシュリファインメントを使用しないため、ここでのケースは人工的です。増加がはるかに小さい場合、断片化を回避するためにメモリの再調整が可能です。しかしながら、

質問:

  1. 実際の科学計算/高性能計算でメモリの断片化が重要になることはありますか?

  2. もしそうなら、どうやってそれを避けますか?たぶん私のマシンモデルは間違っているかもしれません、そしていくつかの重い魔法によるOSは暗黙のうちにメモリを再調整するか、ヒープ上の断片化されたブロックを管理します。

  3. 具体的には、グリッド管理にどのように影響しますか?

回答:


11

メッシュの総メモリ使用量と追加の間接参照については、マットに同意しません。明示的な方法の場合、非常に少数のベクトル(例、2)がすべてのシミュレーション状態を表すのが一般的です。スカラー問題の場合、メッシュの座標を定義するだけでこれよりも多くなる可能性があり、接続が明示的である場合、それは大幅に多くなります。エクスプリシットメソッドを使用した高解像度シミュレーションでは、多くのタイムステップが必要になることが多いため、妥当な量のウォールタイムでモデルの実行を完了するために、かなり小さいサブドメインを使用するのが一般的です。したがって、メッシュを保存するコストのために、メモリ不足になることはそれほど一般的ではありません。

はるかに根本的な問題は、アルゴリズムの各ステップのメモリ帯域幅要件です(たとえば、残差の評価または時間ステップの取得)。非構造化メソッドの場合、これにはいくつかのメッシュベースの情報が含まれますが、通常、すべてのメッシュストレージにアクセスする必要はありません。ソルバーメモリがメッシュメモリを支配している場合でも(多くの暗黙的な方法で一般的です)、シミュレーションは依然としてメッシュトラバーサルの帯域幅要件に頻繁に依存しています。2つの要因があります。

通常のメッシュトラバーサル中に必要なデータは何ですか?

有限要素法では、要素からグローバルへのマップが必要です。1次よりも高い場合、これは多くの場合、自由度を面やエッジなどの中間エンティティに関連付けることによって実装されますが、いったん要素からグローバルへのマップが作成されると、中間エンティティは必要ありません。特に、中間エンティティの接続は、シミュレーションで直接使用されることはありません。その情報は、陰解法ソルバーまたは時間積分器の多くの反復では触れられない可能性がありますが、適応性や新しい関数空間を設定するためには依然として必要です。要素からグローバルへのマップを単純な配列で設定し、この期間中に「メッシュ」データ構造に触れないことが一般的です。その場合、メッシュ自体の格納形式とデータ局所性はそれほど重要ではありません。

有限体積法では、セル体積、面と面の接続、面の面積、および面の法線が必要です。頂点座標または接続が利用可能である必要がないことに注意してください。極端な例(FUN3Dなど)では、他のすべての情報はオフラインの前処理(メッシュ生成)中に破棄され、この縮小表現のみがシミュレーションで使用できます。これは非常に効率的ですが、メッシュの移動やアダプティブリファインはできません。

そのデータはどのようにメモリに配置されますか?

多くのシミュレーションでは、物理学の精度と複雑さは中程度であり、パフォーマンスはメモリ帯域幅によって制限されます。IBM、Intel、AMD、NVidiaの最新のCPUアーキテクチャは、4〜8フロップス/バイトの演算強度をサポートしています。そのような効率的な浮動小数点ユニットでは、アルゴリズムをメモリ帯域幅用に最適化する必要があります。これには、アセンブルされていない高次の方法を好むなど、いくらか深いアルゴリズムの変更が含まれる場合があります(2番目の図の「アセンブルされた」行と(アセンブルされていない)「テンソル」行を比較してください))、ただし、ハードウェアが提供する帯域幅を最大限に活用することから始めることができます。これには、キャッシュが可能な限り再利用されるように、(頂点、面、セルなどの)順序の計算が含まれることがよくあります。また、メタデータを最小限に抑え、適切な数のデータストリームをアクティブ化するために、未知のもののブロックと順序付けを利用します。(通常、3D非構造化シミュレーションは「多すぎる」ストリームで終了しますが、POWER7などの一部の最新のハードウェアは、帯域幅を飽和させるために多くのストリームを必要とするため、意図的にデータを整理してより多くのストリームをアクティブにすることが理にかなっています。)PETSc-FUN3D作業は、古典的な、しかし非構造化された暗黙のCFDのためのこれらのパフォーマンス最適化の非常に関連性の高い議論。

あなたの問題に対する提案

  1. 恐れるなmalloc()。メッシュの現在のリファインを、メッシュのより粗い非アクティブな部分と同じ配列にパックする必要はありません。メッシュの古い部分が必要なくなったときはいつでも、free()それだけです。

  2. 改良後、その改良レベルの適切な順序を計算します(Reverse Cuthill-McKeeが一般的ですが、よりキャッシュ固有の順序を使用することもできます)。負荷の不均衡が妥当な場合(たとえば、10%未満)、この新しい順序をローカルで計算できます(並列分割および再分散なし)。コストはおそらく単一の「物理」メッシュトラバーサルに似ていますが、これらのトラバーサルを2倍以上高速化できます。このステップは通常、メッシュの適応性がそれぞれで発生しないときはいつでも報われます「物理」メッシュトラバーサル。このような頻繁な適応が問題に必要な場合は、小さな変更を加えている可能性が高いため、たまに順序を変更する必要があります。並べ替えが難しくなるため、きめ細かなメモリプールは避けますが、かなり大きなチャンクを使用して、ピーク時のメモリ使用量、注文コスト、増分更新のコストのバランスをとることができます。

  3. 離散化に応じて、「物理」トラバーサルに必要なメモリ帯域幅が少ない縮小表現を抽出することを検討してください。帯域幅の要件が増えるため、不必要なインダイレクションは不良です。また、インダイレクションのターゲットが不規則な場合、キャッシュの再利用が不十分になり、プリフェッチが妨げられます。


帯域幅を占有する中間接続を介したこの問題は、あなたのケースでは排除するのは簡単であり、PETSc DMComplexによって行われます。フィールドデータからメッシュトポロジのストレージを分離します。要素からグローバルへの格納は、私が思うすべてのケースで間違っています。トポロジは、より小さなスペースで同じ情報を持ち、はるかに豊富です。ストレージへのオフセットを使用して、クロージャーのようなトラバーサルを作成します。
Matt Knepley、2012

5

deal.IIでは、古いセルを捨てて新しいセルに置き換えることにより、メッシュを改良します。しかし、新しいものは、削除されたセルによって残されたメモリホールにも配置されます。すべてのセルに対するすべてのループは、メモリ内でセ​​ルが検出された順序で行われ、キャッシュヒットが高く維持されます。

より大きな問題は、セルを定義するデータをどのように保存するかです。もちろん、struct Simplex {Vertex vertices [4];を実行することもできます。int material_id; int subdomain_id; 使用されるブール。void * user_data; };

クラスTriangulation {Simplex * cells; }; ただし、すべてのセルに対するほとんどのループはシンプレックスデータ構造に格納されているデータのサブセットにしか触れず、実際に使用されるのはキャッシュにあるデータの一部のみであるため、これはキャッシュ効率が良くありません。より良い戦略は、次のようなことをすることです:class Triangulation {Vertex * vertices; int * material_ids; int * subdomain_ids; bool * used_flags; void * * user_data; }; すべてのセルに対するループでは、後続の反復はセルを定義するデータの同じサブセットにアクセスする可能性が高いため、先読みキャッシュは実際に使用するデータのみをプリロードし、結果として高いキャッシュヒット率をもたらします。


4

1)いいえ。ソルバーメモリはメッシュメモリをはるかに上回ります。最軽量の陽解法ソルバーを実行した場合でも、メッシュはシミュレーションのメモリの最大25%であり、多くの場合10%未満です。

2)割り当てを分解し、メモリプーリングを使用します。通常、ローカルピースのみを反復処理する必要があるため、メッシュ全体に隣接するチャンクを割り当てる必要はありません。1レベルの間接参照を導入しても、意味のある方法でパフォーマンスに影響を与えることはありません。


この主張に関する言及はありますか?単純な行列のないメソッドは、非常に軽いソルバーフットプリントを持つ必要があります。
aterrel 2011

2
もちろん、マトリックスを使用しない場合は、別の問題になる可能性があります。しかし、マットのコメントが正しいことは簡単にわかります。メッシュの自由度ごとに、マトリックスはこのDoFが結合するのと同じ数のdoubleを格納する必要があります。 (3次元のQ2-Q1 / Taylor-Hood Stokes要素でこれを1回数えます)。これは、メッシュを定義するデータよりもはるかに多くのメモリを必要とすることが簡単にわかります。
Wolfgang Bangerth、2011

0

メモリが不足している場合は、より多くのノードで実行するだけでメモリが増えます。非常に簡単な解決策を持つ問題を解決するために、非常に貴重なリソース(人間の脳)を浪費しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.