Fortranの「モジュール」を制する者は、HPCの荒波を制する
こんにちは。元宇宙航空研究機関で、数千コアをぶん回す数値計算コードの最適化を長年やってきた者です。
皆さんは今、C言語やPythonといった素晴らしい言語からFortranの世界へ飛び込もうとしていますね。Fortranは「古い」と思われがちですが、実は「コンパイラが計算性能を極限まで引き出すために、最も誠実に応えてくれる言語」です。
今日は、そのFortranの心臓部とも言える「モジュール(MODULE)」と、切っても切れない「依存関係」の泥臭いお話をしましょう。
—
1. モジュールは「高性能な設計図の保管庫」
C言語でいうところのヘッダーファイル(`.h`)とソースファイル(`.c`)の役割を、Fortranでは一つの`MODULE`に統合できます。
Pythonで`import`するように、Fortranでは`USE`文を使います。しかし、ここにはFortran特有の「強み」があります。それは「コンパイル時にインターフェースが完全にチェックされる」という点です。引数の型や配列のランク(次元数)が食い違っていれば、実行時ではなくコンパイル時に容赦なくエラーを出してくれます。これは、スパコンで1週間回すコードにおいて、実行直前でクラッシュする悲劇を未然に防ぐための強力な保険なのです。
まずはここから:モジュールの基本形
! 数値計算用のモジュール定義
module math_utilities
implicit none ! 暗黙の型宣言を禁止(これ鉄則です!)
private ! デフォルトで外部から見えないようにする(カプセル化)
public :: compute_kinetic_energy ! 必要な関数だけ公開
contains
function compute_kinetic_energy(mass, velocity) result(energy)
real(8), intent(in) :: mass, velocity ! 8バイト実数(倍精度)
real(8) :: energy
energy = 0.5d0 mass velocity2
end function compute_kinetic_energy
end module math_utilities
—
2. コンパイルの「順番」という名の悪魔
Fortranのモジュールを使用すると、ソースコードは「依存関係」で結ばれます。`A`というモジュールを`B`で`USE`する場合、必ず`A`を先にコンパイルしなければなりません。
これを手動でやっていると、プロジェクトが大きくなった瞬間に地獄を見ます。そこで登場するのがMakefileです。
現場で使うMakefileのテンプレート
コンパイラ(ここでは`gfortran`や`ifort`を想定)は、`.mod`という中間ファイルを生成します。これが依存関係の鍵です。
コンパイラとオプション
FC = gfortran
FFLAGS = -O3 -march=native # 最適化フラグ:CPUの性能をフルに使う
ソースとオブジェクトの定義
SRCS = math_utilities.f90 main.f90
OBJS = $(SRCS:.f90=.o)
ターゲット
app.exe: $(OBJS)
$(FC) $(FFLAGS) -o $@ $^
依存関係の記述:main.oはmath_utilities.modに依存している
main.o: math_utilities.mod
モジュールの生成ルール
%.mod: %.o
@: # 何もしない(.oが生成される過程で.modができる)
%.o: %.f90
$(FC) $(FFLAGS) -c $<
clean:
rm -f .o .mod .exe
---
3. なぜ「泥臭い」管理が必要なのか
ここからは現場の極意です。
Fortranは「列優先(Column-major)」というメモリ配置ルールを持っています。配列をループで回す際、一番左のインデックスから順にアクセスしないと、CPUのキャッシュが効かず、計算速度が10倍以上落ちることがあります。
モジュールで計算ロジックを隠蔽する際、「引数として渡される配列が、どうメモリ上に並んでいるか」を意識したインターフェース設計を心がけてください。
- アドバイス: `USE`文を使うとき、不用意にモジュール全体を読み込むのではなく、`USE math_utilities, only: compute_kinetic_energy`のように、必要な機能だけを明示的に指定しましょう。これにより、名前空間の汚染を防ぐだけでなく、コンパイル時の依存関係も整理され、ビルド時間が短縮されます。
—
最後に:皆さんへ
「Fortranは難しい」と感じるかもしれません。しかし、コンパイラと対話し、メモリの配置を意識し、モジュールで綺麗に構造化されたコードが、スパコン上で秒速数テラフロップスを叩き出す瞬間、皆さんはきっとこの言語の虜になるはずです。
まずは小さなモジュールを一つ作り、Makefileを書いてみてください。エラーが出ても大丈夫。それはコンパイラが「もっと効率的な書き方があるよ」と教えてくれているサインですから。
次は、モジュールの中での「派生型(Derived Type)」によるデータ構造化についてお話ししましょう。それでは、良きHPCライフを!

コメント