- 締切済み
並列化プログラムの作成方法について
物理計算の並列化についてお尋ねします。計算機環境(GPU, メモリ分散(ハブ)、メモリ共有(CPU内での並列))、コンパイラの選択とかいろいろ条件があると思います。また、作りこみの度合い(本気度)によっても違うと思います。特に並列計算は並列化の度合いによって速度が急激に伸びるなどいろいろ特性があると思います。 現時点では、 通常のパソコン(Core-i7)で、コンパイラはintel fortran, OSはWindows10というごく普通の環境です。Cygwinのgfortran, Visual studioなどもあります。 物理プログラムは、構成として以下のようです。 2次元空間の時間発展の計算です。 do n=1,nt do i=1,nx ! x方向格子へのループ do j=1,ny ! y要綱格子へのループ enddo ! x方向格子ループの端 enddo ! y方向格子ループの橋 enddo ! 時間方向ループの終端 stop end 時間発展のループの中に、空間方向のループが何回も出てくるという構成です。計算が遅くなる理由は空間方向の格子数が極端に増えるからです。 このような場合、計算の速度を向上させるための並列化の方法についてゼロベースで教えて頂きたいのですが。ゼロベースなので、何から手を付けるべきかということですが。 よろしくお願いします。
- みんなの回答 (5)
- 専門家の回答
みんなの回答
- ki073
- ベストアンサー率77% (491/634)
No.2,4です。 並列化したつもりでも、かえって遅くなることはよくあります。 こちらはLinux+PGIコンパイラでやっていますので、Windows+Intelコンパイラとは違うかもしれませんが、実際にマルチスレッドで動いていますか? 自動並列化の場合は、並列化できないメッセージがでてくる場合も多いですので確認してください。 >内側のループは2次元ですが、それが10個ぐらいあります。 do n=1,nt直下の外から二番目のループが10個ぐらいということでしょうか? 複雑そうですのでプロファイラで実行時間の測定をお勧めします。どこの最適化が効果があるかわかります。 >ifなどの制御系、ファイル出力もありますが if文は並列化にはあまり影響ありませんが、SIMD利用を確実に阻害します。それとファイル出力がある場合にその部分は並列化不可能です。最内ループのif文は可能な限り外側のループに出します。それにより計算量が2倍程度になっても全体の速度が速くなることも十分あります。GPUの場合は10倍程度増えても効果があります。
- ki073
- ベストアンサー率77% (491/634)
No.2です。 メモリ共有型を前提に書きましたが、パソコンレベルでしたらメモリ分散型は考えない方が良いように思います。 高速なネットワークを構築する必要がありますので、かなり高価なります。スーパーコンピュータを使う前提ではないのでしたら、GPUを使う方法を現在は選んだ方が良いと思います。GPUを使って速くなることは稀ですが、並列化というよりはベクトル化がうまくできた場合は劇的な効果が期待できます。
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
I,j の多重loop内での処理において互いに独立なら、すなわち(I,j)での処理が(i',j')での処理に依存しないのなら、GPGPU(CUDA,OpenCL,etc.)で計算させるのがおそらく最も高速。
- ki073
- ベストアンサー率77% (491/634)
市販コンパイラには自動並列化するためのオプションがあるはずです。それと出力される最適化情報を頼りにすると、並列化の重要なヒントが得られます。 ループの中の処理を書いていないのでアドバイスのしようがないのですが、一般的なこととしては、 ループの実行される順番が変わっても正しい答えがでることが並列化には最低限必要です。もし順番に依存するのでしたら、それを解消する手段を考えます。 外側のループでそのようなことが出来れば良いのですが、それが無理な場合は内側だけでもそれを可能なようにします。 並列化とは直接関係ないですが、内側のループで可能な限り連続したメモリに順次アクセスできるようにします。配列を使っていると思いますが、アクセスする順番をメモリの連続した領域になるように出来ればそうします。このことで、CPUキャッシュの効果がでますし、場合によってはSIMDが使えるようになるため、並列化より効果が期待できます。 ループの中身を書いてもらえれば、アドバイスが可能ですが
お礼
回答ありがとうございます。 元発言のプログラムの一番外側ループが時間発展、その内側は空間方向のループです。内側のループは2次元ですが、それが10個ぐらいあります。また、それぞれはサブルーチンに飛びます。ifなどの制御系、ファイル出力もありますが。2次元配列の場合、結局メモリの状態としては1次元であり、あちこちに飛ばないようにプログラム化するというのは常とう的なことにも気を付けていますが。 並列化を全く考慮しないでソースを描いたあと、intel fortranのーQparallelオプションでコンパイルしても早くなりませんでした。少し遅くなった感じでしたが。 私の現時点の希望としては、並列化していきなり早くなるということよりもこういう風な努力をすることが計算を早くすることにつながるということですね。 例えば、非常に短いプログラムで理解するというのはどうでしょうか。ポアソンソルバーとかですが。 どうでしょうか。
- trytobe
- ベストアンサー率36% (3457/9591)
並列化は、個々のプロセッサや分散システム(ネットワーク構成や台数など)に応じて、「コンパイラで最適化された分散化をさせる」のが王道です。 自分で分散処理システムに応じたコードを書き分ける、などということはしないのです。 並列分散処理 コンパイラ - Google 検索 https://www.google.co.jp/search?q=%E4%B8%A6%E5%88%97%E5%88%86%E6%95%A3%E5%87%A6%E7%90%86++%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9
お礼
回答ありがとうございます。 ソースの作成時に並列化を意識するか、ということは問題になるのではないかと思いますが、どうでしょうか。 つまりハードウェア環境とコンパイラに依存したコード化を考えていくということですが。 私は全くそのことを意識しないでコード化し、インテルフォートランで-Qparallel オプションで実行ファイルを作成して実行したところ、遅くなりました。具体的にどうするのかなと思いますが。
お礼
回答ありがとうございます。 手持ちはWindows10, intel Fortran 11.xxというところです。ビデオはnvidia限定なのでしょうか。GPUについては書籍もある程度ありますが、そのとおりに実行するには事前条件が合致している必要があるのではないでしょうか。例えば、CygwinのOpenMPのようなものだとゼロベースから始められるわけですが、設定が決まっていると敷居が高い感じがしています。