はじめに
処理に時間のかかるプログラムで、途中経過のログをファイルに出力してチェックするなんてことはよくあると思う。でも gfortran で何も考えずにファイルに write するプログラム書くと、出力がバッファされてヘタするとプログラムが終了するまでファイルに書き出さなかったりするんだ。ΩΩΩ<ナ、ナンダッテー
gfortran の出力バッファリングについて
タイトルに gfortran ってつけてるけど他の Fortran コンパイラでも似たようなものじゃないかな? しらんけど。
ログを出力するサンプル
まずはログ出力のサンプルプログラム。1秒毎にカウンタを計20回ファイルに出力するだけ。
program test_io_buffering
implicit none
integer :: u, i
open(newunit=u, file='test.log', status='replace')
do i = 1, 20
write(u, '(*(g0))') 'i = ', i
call sleep(1) ! SLEEP is GNU extension
end do
close(u)
call exit(0) ! EXIT_OK
end program test_io_buffering
これを gfortran でコンパイルして実行する。プログラムが終了する前に test.log の内容を確認すると空のファイルになっているのに、プログラム終了後に確認すると 'i = 1' から 'i = 20' までちゃんと出力されている。
いい忘れてたけど open 文の newunit 指定子とか write 文の g0 フォーマット編集記述子は Fortran 2008 で、sleep は gfortran なんでそうでないとこでは適当に読み替えてほしい。
どうしてこうなった
これはプログラムの出力が一旦バッファに溜められてまとめてファイルに書きだされるようになっているから。
バッファに溜める理由は高速化のため。
通常ファイルじゃなくて標準出力 (UNIT=6) や標準エラー出力 (UNIT=0) に出力する場合、端末に出力するときはバッファされないんだけれど、ファイルにリダイレクトするとバッファされる。パイプに対してはバッファされないようだ。
UNIT | コマンド | バッファの有無 |
---|---|---|
6 | ./a.out | バッファされない |
6 | ./a.out > test.log | バッファされる |
6 | ./a.out 2>&1 | cat > test.log | バッファされない |
0 | ./a.out | バッファされない |
0 | ./a.out 2> test.log | バッファされる |
0 | ./a.out 2>&1 | cat > test.log | バッファされない |
上は UNIX での例だが Windows でもコマンドプロンプトで同じようにして試せる。cat はないがこの例くらいなら代わりに more が使える。ていうか、コマンドプロンプトで標準エラー出力もちゃんとリダイレクトできたんだな。
バッファさせない方法
明示的に flush(unit) を実行する
明示的に flush(unit) を実行するとバッファがフラッシュされる。flush は Fortran 2003 標準。デメリットはめんどくさいこと。
do i = 1, 20
write(u, '(*(g0))') 'i = ', i
flush(u) ! write したあと明示的に flush する
call sleep(1) ! SLEEP is GNU extension
end do
環境変数で指定する
環境変数で GFORTRAN_UNBUFFERED_ALL=y を指定するとバッファしないようになる。値は 'Y' でも '1' でも可。ユニットごとには指定できないし write するたびに flush するのでかなり遅くなるかもしれない。
$ GFORTRAN_UNBUFFERED_ALL=y ./a.out
似たような環境変数に GFORTRAN_UNBUFFERED_PRECONNECTED というのもある。こちらは標準出力と標準エラー出力にのみ作用する。値の指定の仕方は同じ。
変数名からわかるように gfortran 限定。
どうすべきか
ケースバイケースです (おわり)
普通にログ出力として使いたかったらめんどくさくても要所要所に flush を指定するべきじゃないかな。
デバッグ時に使うだけなら環境変数で指定するのもありだと思う。
個人的には open のときに指定したかった (ベンダ拡張でそういうのもあるみたい)。
おわりに
他の Fortran コンパイラだとどうなのか
ifort だとどうなんだろうと思って Intel Fortran でもインストールしてみようと思ったら
無償版は廃止 https://software.intel.com/en-us/forums/topic/533638 だそうな。
じゃあもういいや。