「とりあえず定義」で満足していませんか?Fortran派生型とメモリレイアウトの最適化術
こんにちは。数値計算の世界へようこそ。
C言語やPythonでバリバリ開発してきた皆さんがFortranに触れたとき、最初にぶつかるのが「派生型(Derived Type)」の扱いでしょう。
「`type`で構造体を作って、メンバを適当に並べて終わり」……そう思っていませんか?
スーパーコンピュータやHPC(ハイパフォーマンス・コンピューティング)の現場では、その「適当な並び順」が、プログラムの実行速度を10倍遅くすることさえあります。
今日は、Fortranのメモリレイアウトの裏側を覗き、キャッシュ効率を最大化する「職人の並び替え術」を伝授します。
—
1. 派生型は「本の整理棚」である
C言語の`struct`とFortranの`type`は似ていますが、Fortranのコンパイラは、コードの安全性を守るために、人間が想定しない場所へ「パディング(詰め物)」を勝手に入れることがあります。
例えば、こんな型を定義したとしましょう。
type :: Particle
real(8) :: x ! 8バイト
logical :: active ! 1バイト
real(8) :: y ! 8バイト
end type
一見、合計17バイトのように見えますが、実際はそうではありません。CPUはメモリを「8バイト単位」などのキリの良い塊で読み込むのが大好きです。そのため、コンパイラは`active`の後ろに7バイトの隙間を埋め、合計24バイトとして配置します。
これが大量のパーティクル(数百万個!)を配列で持つとき、メモリの無駄遣いが発生し、CPUキャッシュを汚染します。
—
2. 「大きな型から先に」が鉄則
メモリレイアウトの最適化の基本は、「サイズの大きい型から順に並べる」ことです。これだけでパディングによる隙間を劇的に減らせます。
修正前のダメな例
type :: BadLayout
logical :: flag ! 1バイト
real(8) :: val ! 8バイト
! この間に7バイトのパディングが挿入されることが多い
end type
修正後の賢い例
type :: GoodLayout
real(8) :: val ! 8バイト
logical :: flag ! 1バイト
! パディングは構造体の最後だけになり、全体サイズが縮小する
end type
「たかが数バイト」と思うかもしれませんが、科学技術計算で数億回のループを回す際、この数バイトの差がキャッシュミス(メモリからデータを拾いに行く遅い待ち時間)を招き、性能を致命的に削ります。
—
3. 実践:連続アクセスを意識したデータ構造
Fortranは「列優先(Column-major)」言語です。多次元配列のインデックスは、左側の添字が最も頻繁に変わるように設計するのが基本。派生型を配列にする場合も、同様の思想が必要です。
もし、数万個の粒子を扱うなら、`type(Particle), dimension(N) :: p` とするよりも、「構造体の配列」ではなく「配列の構造体(AoS vs SoA)」を検討してください。
! 構造体の配列 (AoS) – メモリが飛び飛びになりがち
type :: Particle
real(8) :: x, y, z
end type
type(Particle), dimension(100000) :: p
! 配列の構造体 (SoA) – こっちの方がSIMD演算(ベクトル化)に効く!
type :: Particles
real(8), allocatable :: x(:), y(:), z(:)
end type
現代のCPUは、メモリから一度に連続したデータを読み込んで計算する「ベクトル化(SIMD)」が最強です。SoAの形にすると、CPUはx座標の塊をガサッと一気にロードして計算できるため、実行速度が驚くほど向上します。
—
4. コンパイラに「配置」を教える
最後に、ビルド設定の小話です。
Intel Fortran (`ifort`/`ifx`) などを使う際、以下のオプションを意識してみてください。
- `-align array64byte`: 配列の先頭をキャッシュラインの境界に合わせます。
- `-O3`: 最適化の基本ですが、これに加えて派生型のメンバ順序を意識すると、コンパイラの「自動ベクトル化」が劇的に効くようになります。
—
若手エンジニアの皆さんへ
Fortranは、古い言語だと思われがちです。しかし、物理現象をシミュレーションするための「最適化の余地」を、ここまで純粋に提供してくれる言語は他にありません。
まずは、自分の書いたコードの派生型を、サイズ順に並べ替えてみてください。それだけで、あなたの計算機は今までよりも少しだけ軽快に動くはずです。
「なぜそうなるのか?」を考え始めたとき、あなたはもう立派なHPCエンジニアの卵です。泥臭いデバッグの先にある、最高のパフォーマンスを目指して頑張りましょう!
また次回、さらにディープな「メモリアクセス最適化」の世界でお会いしましょう。

コメント