3

COMMONブロックを使用してコードのどこでも使用されている配列を格納するmpiバージョンのプログラムがあります。残念ながら、COMMONブロックサイズの配列を宣言する方法はありませんが、実行時にしか認識されません。そこで、回避策として、配列内のALLOCATABLE配列を受け付けるモジュールで配列を移動することに決めました。つまり、COMMONブロックのすべての配列が消失し、代わりにALLOCATEが使用されました。だから、これが私のプログラムで変更された唯一のものでした。残念ながら、プログラムのパフォーマンスは(COMMONブロックの実現と比較して)ひどいものでした。 mpi設定に関しては、各計算ノードには1つのmpiプロセスがあり、各mpiプロセスには1つのスレッドがあります。 私はsimilar質問をここに尋ねたが、私の場合(各プロセスが単一のスレッドを持っている)にどのように適用できるかは考えていない(分からない:))。私はどんな助けにも感謝します。ご覧の通り、ゼロセットは、()は、並列を持っていない割り当て可能な配列の性能

SUBROUTINE ZEROSET() 
    INCLUDE 'FILE_1.INC' 
    INCLUDE 'FILE_2.INC' 
    INCLUDE 'FILE_3.INC' 
    .... 
    INCLUDE 'FILE_N.INC' 

    ARRAY_1 = 0.0 
    ARRAY_2 = 0.0 
    ARRAY_3 = 0.0 
    ARRAY_4 = 0.0 
    ... 
    ARRAY_N = 0.0 
END SUBROUTINE 

「ソースファイル」:ここでは

は、私は(下記の擬似コードで)話していたものを示して簡単な例ですまたはMPIのもの。 FILE_1.INC、FILE_2、...、FILE_N.INCは、ARRAY_1、ARRAY_2、...、ARRAY_NがCOMMONブロックで定義されているファイルです。そのようなもの

REAL ARRAY_1 
COMMON /ARRAY_1/ ARRAY_1(NX, NY, NZ) 

NX、NY、NZは、PARAMETER指令の助けを借りて記述された明確なパラメータです。 私はモジュールを使用する場合FILE_I.INCが

REAL, ALLOCATABLE:: ARRAY_I(:,:,:) 

のように見え、そしてちょうど「を使用FILE_I」に上記のステートメント「『FILE_I.INC』を含める」に変更。ので、私は、すべてのCOMMONブロックを破壊実際には、並列プログラムが実行されると、ある特定のプロセスは全体の(NX、NY、NZ)ドメインを必要としないので、パラメータを計算してからARRAY_I(1回のみ!)を割り当てます。

サブルーチンZEROSET()は、COMMONブロックで0.18秒、モジュールで0.36(配列の次元が実行時に計算されるとき)実行されます。したがって、パフォーマンスは2倍悪化しました。

今はすべてが明確になることを願っています。私はあなたに非常に助けていただければ幸いです。

+2

どのようにこれは並列実行に関連する必要がありますか?パフォーマンスの低下は、シリアル実行ではまだ確認できませんか?あなたはどのくらいの頻度で割り振りますか?仮引数には割り当て可能な属性がありますか? – haraldkl

+1

mpi関連の問題ではないようです。共有メモリまたは分散メモリを使用していますか?メモリのボトルネックが発生している可能性がありますが、すべてを正しく実行した場合は、コードのCOMMONブロック版がうまく動作するため、これは当てはまりません。どのように割り当てたのかのサンプルコードを含めてください。配列を1回(プログラムの開始と終了)に一度だけ割り当てたり割り当てを解除したりすると、パフォーマンスが低下することはありません。 – milancurcic

+0

パフォーマンスは「ひどい」非常に定量的ではなく、どれくらい遅いですか?先に述べたように、最初にシリアルランで問題を確認してください。 – steabert

答えて

3

モジュールで割り当て可能な配列を使用すると、コンパイル時のサイズについてコンパイラが認識しないため、パフォーマンスが低下することがあります。あなたは、このコードの多くのコンパイラではるかに優れたパフォーマンスを得られます:

subroutine X 
    use Y ! Has allocatable array A(N,N) in it 
    call Z(A,N) 
    end subroutine 

    subroutine Z(A,N) 
    Integer N 
    real A(N,N) 
    do stuff here 
    end 

次に、このコード:

subroutine X 
    use Y ! Has allocatable array A(N,N) in it 
    do stuff here 
    end subroutine 

コンパイラは、配列がN×N個と行うループであることを知っているだろうNを超えているとことができますその事実を利用することができます(ほとんどのコードは配列でそのように動作します)。また、「ここで行う」というサブルーチンが呼び出された後、コンパイラは配列 "A"のサイズが変更されたり、メモリ上の場所が移動して再チェックされたと想定しなければなりません。それは最適化を殺します。

これは、ほとんどのパフォーマンスを戻すはずです。

共通ブロックはメモリ内の特定の場所にもあり、最適化も可能です。

0

私はちょうどこれらの理由から、それは配列を使用して、FORTRANのパフォーマンスになると考えることができます:ヒープVSスタック上

  1. 配列が、私は、これは巨大なパフォーマンスの影響を与える可能性があります疑います。
  2. それを行うための最善の方法は、実際に私が推測するusing arrays efficiently
+0

リンクが壊れているので、同じ記事と思われるものを編集しました。私が間違っている場合はそれを修正してください。 – astay13

0

にこのページを参照してください、配列に依存しているため、ここでの問題は、ヒープメモリ対スタックとの組み合わせで、ある、サブルーチンに配列を渡します確かにコンパイラの最適化に基づいています。使用しているコンパイラによっては、より効率的なメモリブランキングが行われる可能性があります。また、固定されたメモリチャンクでは、サブルーチン内の範囲と場所を確認する必要もありません。したがって、固定サイズのアレイでは、オーバーヘッドはほとんど発生しません。 このルーチンは非常に頻繁に呼び出されますか、またはこれらの0.18秒を気にするのはなぜですか? 実際に関連する場合は、0の設定を取り除くことをお勧めします。たとえば、最初の反復ループを分離して初期化に使用すると、追加のメモリアクセスを導入する必要がなくなります。しかし、それはいくつかのコードを複製するでしょう...