Windows 10 Pro の WSL2 の Ubuntu18.04LTSで,Intel Fortran (ifort) version 19.1.2.275,gfortran 7.5.0 (gfortran),および NAG Fortran 7.0 (nagfor) を使用し,沿岸海洋環境数値モデルコードのコンパイルで出会った Warning や Error と対応方針の備忘録です.Libraryは用いず,Fortranソースコードのみからなるプログラムを想定しています.NetCDFを用いて検証したかったのですが,コンパイラ毎に Library を用意するのは大変なので,NetCDFへのリンクの有無をプリプロセッサで制御できるようにし,本記事では外して検証しています.なお,本記事はあくまで個人で開発しているシリアル(並列化されていない)のプログラムを用いた実験結果で,一般性はあまりありません.
bashの環境変数の PATH 設定は full path とします(make で見つけられないため).
結論として,NAG Fortran のコンパイラは未定義(初期化忘れ等)の発見が秀逸で,デバッグに最も威力を発揮しました.
Makefileは以下の様なものを準備しました.
.SUFFIXES : .o .f90
#FLAG_1 = -DNETCDF_OUT
FC = ifort
#FC = gfortran
#FC = nagfor
CPP = icc -E
CPPFLAGS = -P -traditional
CPPARGS = $(CPPFLAGS) $(FLAG_1)
### Intel Fortran
FFLAGS = -auto -heap-arrays -ftrapuv -check all -warn -stand -fpe0 -traceback -g
#FFLAGS = -O2 -fp-model precise
### gfortran
#FFLAGS = -fbounds-check -O -Wuninitialized -fbacktrace
### NAG Fortran
#FFLAGS = -C=undefined -w=unused
TARGET = teem.exe
.f90.o :
$(FC) $(FFLAGS) -c $<
OBJS = mod_util.o mod_globals.o mod_interface.o mod_grid.o mod_grid_bed.o mod_output.o mod_temperature.o mod_salinity.o mod_velocity.o mod_eco_water_param.o mod_eco_bed_param.o mod_eco_flux_param.o teem_flux.o teem_water.o teem_bed.o teem_wavehindcast.o teem_main.o matrix_solver.o matrix_solver_bed.o bcond_surface_stress.o bcond_discharge.o bcond_bed_stress.o bcond_tide.o scalar_common.o teem_flow.o heat_flux.o coriolis.o etc.o bcond_met.o vdiffusion.o hdiffusion.o turbulence_model.o
#LDFLAGS = "${HOME}/local/netcdf4-intel-fortran/4.5.3/lib"
#INCLUDES = "${HOME}/local/netcdf4-intel-fortran/4.5.3/include"
#LIBS = -lnetcdff
LDFLAGS =
INCLUDES =
LIBS =
.F.o :
$(CPP) $(CPPARGS) $*.F > $*.f90
# $(FC) $(FFLAGS) -I$(INCLUDES) -c $*.f90
$(FC) $(FFLAGS) -c $*.f90
# rm -f *.f90
$(TARGET) : $(OBJS)
# $(FC) -o $@ $(OBJS) -L$(LDFLAGS) $(LIBS)
$(FC) -o $@ $(OBJS) $(LIBS)
run :
./$(TARGET) <./input/in2000m1999_1.dat
clean :
rm -f $(OBJS) $(TARGET) *.mod *.f90
Intel Fortran (ifort)
オプション選択と計算結果への影響
標準的なオプションとして以下を採用しています.テストに用いたコードでは -O2
と -O3
の差はないようでした.
FFLAGS = -O2 -fp-model precise # 標準
FFLAGS = -O2 -fp-model precise -traceback # 実行時エラー情報取得
FFLAGS = -auto -ftrapuv -check all -warn -stand -traceback # デバッグ時
FFLAGS = -auto -ftrapuv -check all -warn -stand -traceback -g # デバッグ時 debugger利用
コンパイルオプションの異なる2つの実行形式を用意し,計算結果の実数配列値の差の絶対値の和をとり,チェックしたところ,以下の様になりました.
-O2 VS -O3 # No difference
-O2 VS -O2 -fp-model precise # Significant difference
-O2 -fp-model precise VS -O2 -fp-model precise -fpe0 # No difference
-O2 -fp-model precise VS -O2 -fp-model precise -fpe0 -traceback # No difference
-O2 -fp-model precise VS -O2 -fp-model precise -fpe0 -traceback -xHost # Significant difference
結論として,-fp-model precise
の有無と -xHost
の有無が結果に大きく影響しました.テストケースは1年分の境界条件を用意し,沿岸海洋環境の変動を時々刻々再現するもので,同一の境界条件を用いて複数年の計算を実施し,平衡解(に近いもの)を得ようとするものです.1年程度の計算ではオプションによる差は軽微ですがが,10年分計算すると結構変わります.
Warning への対応
forrtl: warning (406): fort: (1): In call to MYFUNC, an array temporary was created for argument #1 参考
実引数 Array(1,1:10) を仮引数 Dummy(1:10) で受け取る場合はtemporary arrayが作成され,性能が劣化するようです.実引数の配列のメモリアクセスが不連続なためです.
Warning #5268: Extension to standard: The text exceeds right hand column allowed on the line.
1行132桁以内とする
Warning #8889: Explicit declaration of the external attribute is required
外部プロシージャのインターフェースを用意することで対応します.
デバッガー gdb
コンパイルオプション -g
を追加してコンパイルを実行し,実行形式が teem.exe
,標準入力に与えるファイルが ./input/in.dat
とします.デバッガを実行すると詳細なエラー情報が表示されるはずです.
$ gdb teem.exe # gdb 実行形式
(gdb) run <./input/in.dat # run [< 標準入力用のファイル]
抜けるには quit
と入力します.
Tips
NAG Fortran のおかげで変数の値が未定義のエラーがなくなった後で,ifort で -auto
を追加してコンパイル・実行すると(-auto以外のオプションでは問題なく実行できていました),forrtl: severe (174): SIGSEGV, segmentation fault occurred
となりました.デバッガで調べたところ,以下のようなエラーでした.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004ebe27 in teem_ecosystem_water::teem_eco_water_run (
lout3d=<error reading variable: Cannot access memory at address 0xcccccccccccccccc>,
tempt=<error reading variable: value requires 166320 bytes, which is more than max-value-size>,
スタック領域の不足を疑い,$ ulimit -s unlimited
としたところ,問題なく実行できました.一方,コンパイルオプションの -heap-arrays
を加えてコンパイルしても,このエラーは解消されませんでした.
NAG Fortran (nagfor)
トライアルではじめて利用させていただきました.強力なプログラムチェック機能 が売りとのことでしたが,それを実感し,感動しました.
オプション選択と計算結果への影響
NAG Fortran は未定義(初期値設定忘れ)の変数を発見する性能が秀逸です.デバッガーなしで実行時に問題箇所を指摘してくれました.配列の一部の値の指定漏れを指摘したのは NAG Fortran だけでした.
FFLAGS = -C=undefined -w=unused # デバッグ時
Warning への対応
Questionable: ###.f90, line ###: DO index variable ### is not a local variable (it is from module ###)
module procedure内のDOループ変数を(行数節約のため)module変数として定義した場合に現れます.素直に各procedure内で局所変数として定義するのがよいでしょう.
その他
Fortran Builder をWindowsにインストール後,WSL2-Ubuntu の bashターミナルを立ち上げるとsyntaxエラーが発生しました.原因はWindowsのPATHが自動的に取り込まれる際,(x86)のように括弧を含むPATHを解釈できないためでした.Fortran Builderのデフォルトのインストール先は(x86)を含むフォルダ名で,これを適切に変更すれば回避できます.また,Fortran Builder の nagfor.exe を WSL2 の Ubuntuで使えないか試しましたがうまくいきませんでした.本記事はLinux版を使用しました.
The GNU Fortran (gfortran)
NAG Fortran を使用する前にgfortranを使ってみました.Intel Fortranよりも未定義変数を見つける性能が優れていると感じました.
FFLAGS = -fbounds-check -O -Wuninitialized -fbacktrace
参考資料
- Metcalf, M., Reid, J. and Cohen, M. Modern Fortran explained, Oxford University Press, 2018.
- Markus, A. Modern Fortran in Practice, Cambridge University Press, 2012.
- Brainerd, W. S. Guide to Fortran 2008 Programming, 2nd edition, Springer, 2015.
- Curcic M. Modern Fortran - Building efficient parallel applications -, Manning, 2020.
- Chirila, D. B. and Lohmann, G. Introduction to Modern Fortran for the Earth System Sciences, Springer, 2015.
- 牛島省.数値計算のためのFortran90/95プログラミング入門(第2版),森北出版,2020.
- 暗黙の型宣言編著.Fortranによる実践オブジェクト指向プログラミング,2018.
- NAG Fortran コンパイラ 7.0 マニュアル
- Damian Rouson This is not Your Parents' Fortran: A scalable, Parallel, Functional, OO PDE Solver
- Wikipedia: Partitioned global address space (PGAS) (和訳)