【入門編】Coarrayを用いた1次元領域分割(ドメイン分解) – モダンFortran言語仕様と実践実践マスター

Fortranの「Coarray」で挑む、並列計算の深淵へ

こんにちは。長年、スパコンの冷却ファンの音を子守唄にしてきた元・数値計算アーキテクトです。

C言語で`MPI_Send`や`MPI_Recv`を書いて、デッドロックに頭を抱えた経験はありませんか?あるいは、Pythonの`multiprocessing`でGIL(Global Interpreter Lock)に阻まれ、「なぜ並列化したのに遅くなるんだ!」と絶叫したことは?

FortranのCoarrayは、それらとは全く異なる哲学を持っています。言語仕様そのものに「並列実行」が組み込まれているため、まるで共有メモリと分散メモリのいいとこ取りをしたような、非常にエレガントな並列化が可能です。今回は、科学技術計算の王道、「1次元ドメイン分割」を通して、その魅力を紐解いていきましょう。

1. Coarrayの基本思想:プログラムは「コピー」される

まず、頭を切り替えてください。Coarrayを用いたプログラムは、起動すると「イメージ」と呼ばれる複数のコピーが同時に立ち上がります。

  • CやPythonが「メインプロセスから子を生成する」という主従関係を持つのに対し、
  • FortranのCoarrayは「同じプログラムが、個別の個室(イメージ)で一斉にスタートする」という対等な関係です。

自分のイメージ番号を知るには `this_image()` を、全部でいくつイメージがあるかを知るには `num_images()` を呼び出すだけ。これだけで、各イメージは自分の担当範囲を決定できます。

2. 1次元ドメイン分割の実装:境界をどう受け渡すか

物理的な領域を $N$ 個の点に分割し、それを $P$ 個のイメージで分け合うとします。ここで一番重要なのは、隣のイメージが持っている「境界データ」をどう受け取るかです。

Coarrayでは、配列定義に `[]` をつけるだけで、他のイメージのメモリを直接(論理的に)覗きに行けます。

program domain_decomposition
implicit none
! 各イメージが持つ、隣接データのバッファを含む配列
! [] がついているのがCoarrayの証。これだけで遠隔参照可能!
real, allocatable :: local_data(:)[:]
integer :: n_local, n_total, i, me, np

me = this_image()
np = num_images()
n_total = 100
n_local = n_total / np

! +2は左右の境界(ゴーストセル)分
allocate(local_data(0:n_local+1)[])

! 各イメージで初期値を設定
local_data = real(me)

! ここが重要:隣のイメージの境界を同期して取得する
! 「同期」をとらないと、相手が書き込む前に読んでしまう(レースコンディション)
sync all

! 左隣のイメージ(me-1)の右端を、自分の左境界(0番目)にコピー
if (me > 1) then
local_data(0) = local_data(n_local)[me-1]
end if

! 右隣のイメージ(me+1)の左端を、自分の右境界(n_local+1番目)にコピー
if (me < np) then local_data(n_local+1) = local_data(1)[me+1] end if print , "イメージ", me, "の境界値:", local_data(0), local_data(n_local+1) sync all deallocate(local_data) end program ---

3. なぜ「同期(Sync)」が必要なのか?

上記のコードにある `sync all`。これは単なる待機ではありません。メモリの整合性を保証する「メモリバリア」です。

Fortranのコンパイラは、最適化の鬼です。`local_data` への書き込みと読み込みが順序通りに行われるよう、コンパイラに対して「ここまでは絶対に待て」と指示を出すのがこの `sync` の役割。これを怠ると、コンパイラが「お、この計算結果は使われてないな」と勝手に最適化で計算自体を消し去る(いわゆるデッドコード削除)ことがあり、デバッグで死ぬほど苦労することになります。

4. コンパイルと実行のヒント

モダンなFortran(gfortran 10以降など)であれば、以下のフラグを意識してください。

コンパイル:-fcoarray=lib を指定し、OpenCoarrays等のライブラリをリンクする
gfortran -fcoarray=lib -o domain_test domain_test.f90 -lcaf_mpi

実行:4つのイメージで走らせる
cafrun -n 4 ./domain_test

現場の知恵:パフォーマンスの泥臭い話

Coarrayは便利ですが、「列優先(Column-major order)」というFortranの伝統を忘れてはいけません。
多次元配列を扱う際、一番左の添字が連続するようにループを回さないと、キャッシュヒット率が劇的に低下します。Coarrayで他イメージのデータを頻繁にアクセスする場合、ネットワーク負荷も無視できません。可能な限り「通信はまとめて、計算は重く」が鉄則です。

最後に:まずは小さな一歩から

Fortranは古い言語と言われますが、並列計算という文脈においては、CやPythonよりも遥かに「科学者の意図をCPUに直接叩き込める」言語です。

まずは、自分の環境で `sync all` を使って、イメージ間で変数をやり取りするところから始めてみてください。画面に各イメージが正しくデータを読み込めたと表示された瞬間、あなたも立派なHPC(高性能計算)エンジニアの仲間入りです。

何か詰まったら、いつでも聞いてくださいね。計算機科学の深淵は、まだまだこれからですよ。

コメント

タイトルとURLをコピーしました