Fortranで「速さ」を極めるための第一歩:CONTIGUOUS属性がもたらす魔法
こんにちは。長年、スパコンの冷却ファンの音を聞きながら、数値計算コードの最適化と格闘してきた者です。
C言語やPythonからFortranの世界に飛び込んできた皆さん、ようこそ。Fortranは「古い」と言われがちですが、行列計算や物理シミュレーションにおいて、現代でも最強の武器の一つであることは間違いありません。
しかし、ただFortranで書けば速いわけではありません。コンパイラを「味方」につけ、CPUの性能を限界まで引き出すための「魂の書き方」があるのです。今日はその中でも、最も基本的かつ破壊的な威力を発揮する`CONTIGUOUS`(連続的)属性についてお話しします。
—
なぜ「メモリの連続性」が重要なのか?
皆さんは、図書館で本を探すときを想像してみてください。
本が棚に隙間なくきれいに並んでいる(メモリが連続している)なら、端から順に手を伸ばして取っていけますよね。これがCPUにとっての「理想的な状態」です。
ところが、C言語などでポインタをこねくり回したり、Fortranで巨大な配列の一部を切り出して渡したりすると、メモリ上では本がバラバラに散らばっている状態になります。CPUは「次のデータはどこだ?」と探し回る羽目になり、計算速度は劇的に低下します。
Fortranの`CONTIGUOUS`属性は、コンパイラに対してこう宣言するものです。
「この配列はメモリ上で途切れることなく並んでいるから、安心してガッツリとベクトル化(SIMD化)してくれ!」
—
ステップバイステップ:実際に書いてみよう
まずは、この属性がない場合とある場合の書き方を比較してみましょう。
1. 悪い例(コンパイラが疑心暗鬼になるコード)
プロシージャへ配列を渡す際、ポインタや部分配列を使うと、コンパイラは「あ、これメモリが途切れてるかも…」と心配して、安全策(=遅いコード)を生成してしまいます。
subroutine process_data(arr)
real, intent(inout) :: arr(:) ! 連続している保証がない
! コンパイラは「非連続かもしれない」と仮定して、
! 一時的なコピーを作成したり、ベクトル化を諦めたりします。
arr = arr 2.0
end subroutine
2. 良い例(CONTIGUOUSで確約する)
このように`CONTIGUOUS`を付けることで、コンパイラは迷いを捨て、最速の機械語を吐き出します。
subroutine process_data_fast(arr)
! ここで連続性を保証!
real, intent(inout), contiguous :: arr(:)
! これによりコンパイラは自信を持ってSIMD命令を適用できます
arr = arr 2.0
end subroutine
—
実践:ビルド時にコンパイラへ「魂」を伝える
コードを書くだけでは不十分です。コンパイラに「最適化してくれ!」という強い意志を伝えるフラグを渡す必要があります。
例えば、Intel Fortran (ifort/ifx) や GCC (gfortran) を使う場合、以下のようなフラグを付けるのが現場の常識です。
- Intelの場合: `-O3 -xHost -qopt-report`
- `-O3`: 最強の最適化。
- `-xHost`: 実行環境のCPU性能をフル活用する命令セットを使う。
- `-qopt-report`: コンパイラが「ベクトル化できたか?」をレポート出力してくれる。
もしレポートを見て「Vectorization: No」と書かれていたら、`CONTIGUOUS`が足りない証拠です。レポートとにらめっこしながら、コードを洗練させていく。この泥臭い作業こそが、シミュレーション屋の醍醐味です。
—
若手エンジニアへのアドバイス
「とりあえず動くコード」を書くのは簡単です。しかし、数百万ステップの計算を回すとき、1%の最適化が数時間の短縮に繋がります。
1. まずはプロファイラを通す: どこがボトルネックか、勘ではなくデータで知る。
2. 型とメモリを意識する: Fortranは「列優先(Column-major)」です。ループの最も内側で、最初の添字が動くように書くのが鉄則です。
3. `CONTIGUOUS`を恐れない: コンパイラに嘘をついてはいけませんが、連続していると確信できる場所には、迷わずこの属性を付与してください。
Fortranは、あなたが書いたコードの意図を汲み取り、限界まで速くしようと努力してくれる誠実な言語です。最初は少し厳格に感じるかもしれませんが、慣れてくるとこの「厳格さ」が、大規模計算における最強の安心感に変わります。
さあ、皆さんのコードでも`CONTIGUOUS`を探して、ぜひ最適化を試してみてください。もしコードの挙動で悩んだら、いつでもまた戻ってきてくださいね。応援しています!

コメント