一般的にdo-loop内での関数呼び出しはコンパイラによるベクトル化・最適化を阻害する要因になる。 一方で、コード管理の観点等から、do-loop内関数呼び出しの形式での実装が好ましい場合もある。 例えば MRI.COM での密度計算がこれにあたる。 MRI.COM では include 文を用いてコード本体を一括管理することにより、高速化とコード管理の両立を図っている。
Intel Fortranでは -ipo オプションの利用により、複数ファイル間で手続き間の処理を最適化することができる。 例えば density.F90 で密度計算のスカラー関数を定義し、それを別ファイルの手続きで利用する場合も、-ipoオプションを用いればインライン展開などの最適化が期待される。
インライン展開のような最適化にはコンパイラ依存がある。 例えば、gfortranには、複数ファイル間を跨いだ手続き間の最適化を実施するようなオプションは存在しなさそうである。 このようなコンパイラではモデルの実行速度が低下する。
一方で、gfortranのようなコンパイラでも、同一ファイルに定義された手続き間ではインライン展開等の最適化は実施されると期待して良さそうである。 密度計算コード本体を1つのファイルに記載し、密度計算を要するファイル毎に、密度計算スカラー関数を定義してあげれば、コードの一括管理を実現しつつ、インライン展開などの最適化が有効になることが期待される。 例えば MRI.COM の stratification.F90 では以下のような実装がなされている。
module oc_mod_stratification ... contains ... subroutine stratification__stable ... do k = 1, ktmp do jjj = numj4(k) + 1, numj4(k+1) i = ii4(jjj) j = jj4(jjj) call stratification__ts2sig(trcal(i,j,k,1),trcal(i,j,k,2),sigma_theta(i,j,k)) end do end do ... end subroutine stratification__stable ... subroutine stratification__ts2sig #include "Eos/ts2sig_center.inc" end subroutine stratification__ts2sig ... end module oc_mod_stratification
この例では、eos/ts2sig_center.inc に水温、塩分から海面基準のポテンシャル密度を計算するコード本体が記載されている。
do-loop内での関数呼び出しは、SIMDと呼ばれるベクトル化を阻害する場合があり、計算速度が大きく低下する。 密度計算のような手続きは本来ベクトル化に影響しないものである。 このような関数では OpenMP の指示行を用いることで、do-loop内での関数呼び出しを実施する場合でも SIMD 化を促進することができる。 具体的には指示行 !$omp declare simd を、implicit none や use 文の前に挿入する。
例えば、上記の eos/ts2sig_center.inc は以下のような内容になっている
!$omp declare simd use oc_mod_eos, only: dc_a, dc_b, dc_c, dc_d implicit none real(8), intent(in) :: t, s real(8), intent(out) :: sig !> [kg/m3 - 1000] real(8) :: t2, t3, t4, t5, s05 #include "eos/ts_prep.inc" t5 = t4*t #include "eos/ts2sig.inc"
注意点