トップ «前の日記(2008-03-17) 最新 次の日記(2008-03-19)» 編集

Orz日記 by Akio Morita

ToDo:

  • 15 SAD Fit[]回りの障害事例の解析
  • 10 smart pointer版PEGクラスの再実装(Left Recursionまわり)
2006|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|06|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|07|08|09|10|11|12|
2013|01|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|06|07|08|10|12|
2016|01|02|03|05|06|08|10|11|
2017|01|02|03|04|05|06|07|09|10|11|12|
2018|01|02|03|04|06|07|08|09|10|11|12|
2019|01|03|04|05|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|

2008-03-18 [長年日記]

_ [Fortran]libgfortran解析

Fortran I/O側でのバッファ管理の形態は、OPEN文が実行された時点での fileの種類に依存し、実際のI/O時にfile descriptorがどんな 実体と結びついているかは考慮されていない。 つまり、外部から FNUM + dup2(2)で上書きするという使い方は、 保証外の使用法である。(当たり前と言えば、当たり前ですよね)

バッファの管理形態としては、次の3種に分類できる。

種別条件read(2)の呼び出しパターン
unbufferedisatty(3)が真要求された読み込み量だけ read(2)を発行する
special fileS_ISREGが偽バッファを埋めるために、read(2)を一度だけ呼び出す
regular fileS_ISREGが真バッファが埋まるまで、read(2)を繰り返し呼び出す
  • regular file(一般のファイル)では、FGETC intrinsicを使ってもバッファフィルのために read(2)でBlockingが発生する可能性が有る。
  • special file(/dev/nullpipe)の場合は、kernel buffer側が空でなければ、Non-Blocking的な動作をする。
    • ただし、kernel buffer側から Fortran I/Oバッファへ読み込めるだけ読み込む。
    • 結果、I/O intrinsicで要求されたよりも多くのデータがkernel buffer側から読み出され空になる可能性が有る。
  • unbuffered(端末デバイス)では、I/O intrinsicの要求された量しか読み出さない。
    • 結果、FGETC intrinsicは 1byte readのシステムコールを発行する。

つまり、SADInspectで起きてる問題は、special file型としてOPEN された Logical Unit Number(LUN)へ socketを結びつけてネットワークから uni-byte streamを受け取る際に、SelectUnit[](ioctl(FIONREAD))で kernel buffer側に溜まっているデータ量を確認し Read[, {n*Byte}]で 溜まっているデータだけを受け取ろうとするが、ioctl(FIONREAD)発行後 read(2)システムコール呼び出しまでに新たに受信されたデータが、 Fortran I/O側のバッファにコピーされ、Read[]で指定した以上の データが kernel bufferから取り出されるために、適切な受信が 出来ない現象であると説明できます。

Fortran I/Oを使う限り、Fortran I/O側のバッファに溜まっている データ量を拾う手段が無いことには解決しません。 また、Fortran I/Oの具体的な実装はコンパイラ依存なので、 言語仕様にそうした手段が組み込まれない限りコードの移植性は望めません。

従って、これを解決するには、unbufferedにするしかありません。 具体的には、itopenbuf_内で仮想端末を確保してOPEN文に渡せばよい。 ただし、FGETCを用いた現状の uni-byte stream読み込みの実装では 著しいパフォーマンス劣化が予測されます。

_ [SAD][Fortran]仮想端末デバイスを使った itopenbuf_

仮想端末デバイスを一時ファイルにした itopenbuf_を実装。

Revision 1482は、USE_NEW_FORTRAN_OPEN_SIM=YESな状態でコンパイルした itopenbuf_はposix_openpt(3),grantpt(3),ptsname(3),revoke(2)を使った 仮想端末デバイスの確保を行いOPEN文でptyを開いたのち、 そのfile descriptor/dev/nullで置き換えて、 仮想端末をクローズする。

以前のmkfifo(2)ベースの動作に戻すには、 COPTへ-DUSE_ITOPENBUF_MKFIFOを追加こと。

_ [SAD][Fortran]仮想端末デバイスを使った itopenbuf_の効能

仮想端末版 itopenbuf()で作った Logical Unit Numberへ結びつけた pipe(2)での動作を検証してみました。

コンパイラPipe[]へのRead[]の動作
g95 0.91 20080220unbuffered
g77 3.4.6buffered
gfortran 4.2.4 20080305(prerelease)unbuffered
gfortran 4.3.1 20080306(prerelease)unbuffered
Intel Fortran 7.1unbuffered
Intel Fortran 8.1buffered
  • g77は、Fortran I/Oのバックエンドが stdioになっている。
    • Pipe[]へのWrite[]もbuffered(Flush[]するまで、kernelに渡らない)なので、これはstdioのバッファリングの挙動と思われる。
  • Intel Fortran 8.1は、Pipe[]へのWrite[]はunbufferedな動作になっているのが謎。

Intel Fortranに関しては、最新の Version 10は持ってないので判断を 保留しますが...g77に関しては「窓から投げ捨てろ」ということですね

_ [tDiary]tdiary-2.2.1へ追従

2008/02/29にリリースされていたのね...

_ [Fortran]gfortran 4.4.0 20080314 (experimental)

explの修正が入った。

explを使った long double系の intrinsicは、 explが提供される環境でのみ組み込まれるよう変更されました。

_ [SAD][Fortran]gfortran 4.4.0でコンパイル

20080314の snapshotだと問題なく動作する。 becnh2.sadで見る限り、4.3よりも少し早い?


カテゴリー: Admin | Emacs | EPICS | Fortran | FreeBSD | GCC | hgsubversion | IPv6 | KEKB | LHC | Lisp | LLVM | MADX | Ryzen | SAD | samba | tDiary | unix | WWW | YaSAI | お仕事 | イベント | 出張 | 宴会 | 数学 | 艦これ | 買いもの | 追記 | 雑記