5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Modern Fortran のコンパイルとデバッグ

Last updated at Posted at 2021-02-14

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

参考資料

5
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?