トップ 最新 追記

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|

2008-03-05 [長年日記]

_ [SAD]最適化への考察

ここ最近、SADをコンパイル時の最適化レベルを上げてコンパイラのバグを 踏んづける事例が何例か報告されていますが、i386系で GCC使う場合 -O1-O2ってそんなん差が出ます? 多分、Intel Fortranを使う方が全然はやいと思うのですが... (昔からGCCの-O2は怪しい環境が多いのです)

あと、数値計算だと内部的にいろんなコードが使っている 線形代数や FFTのコードを最適化済みの(例えば、SSE/Multi Threadに 最適化した)ライブラリに置き換えた方が、早くなりそうな気がします。 おまけに、外部化すれば保守が簡単に...

特に、線形代数ライブラリーに関しては、BLAS/LAPACKという デファクトスタンダードな APIがある上に、有償ですが ベンダーが最適化済みのものを提供しています

FFTに関しては、fftwかな?

以下の三つのファイルがコンパイル出来ないのでSADのベンチマークは 取れていませんが、フリーのコンパイラでは LLVM-GCCが期待大です (小さなプログラムでは Intelコンパイラに近い性能が出ます)

  • src/tfearray.f
  • src/tfeexpr.f
  • src/tfbessel.f

2008-03-11 [長年日記]

_ [unix]シェルの検索パスに使える文字

よく考えれば当たり前の話ですが、シェルの検索パスとして使える パス名を構成する文字には":"は含まれません

所謂、Bourne shell /bin/shの検索パスは、環境変数PATHに ":"を区切り文字として列挙されるので、":"を含んだパスは 使えません。「バックスラッシュエスケープ出来る」と思う人も 居るかもしれませんが、PATH変数としては"\\"は ただの文字リテラルなのでエスケープ出来ません。

これが、/bin/cshだとシェル変数pathは空白区切りで 設定するので、csh自身がコマンドを探す場合は問題なく 使えてしまうのですが、コマンド検索が/bin/shや system call 経由になった瞬間に誤作動しますので、要注意です。

似たような例に、makeのソースやターゲット名に":"を 含むファイル名が使えないと言う罠もありますね

_ [SAD]Messageについて

SADScriptの関数は、内部エラーに関して itfmessage_()関数経由で エラーを通知するものがあります。 これらのエラー通知は、関数の返り値ではなく Messageとして送出され、 Messageが送出された事実はCheck[]関数でトラップすることが 出来るのですが、発生したMessageとその内容を知る術が実はありません Orz コマンドラインからの実行に対しては、MessageList[]関数がありますが Messageの名前だけで付属のパラメータは記録されていません。

つまり、ユーザー定義の関数で、例外が起こり得る関数を呼び出す際に Check[]で例外をトラップし、処理可能な例外は関数内で処理し、 処理できない例外に対しては関数の外側に例外を転送する処理が書けません。

仕方ないので、Add\$Message[]関数に細工して\$MessageLastに 最後に送出されたメッセージを記録するようにしました。

が、Check[]関数では例外を検知しますが、例外発生時点で式の評価が 止まるわけでは無いので、真面目に例外処理を書こうとすると面倒ですね。

Try[]ブロック構文でも、新設すべきかな?

C++の例外機構を知っている人間が勘違いしやすいものに、Catch[]関数が あるのですが、これはThrow[]関数による式評価からの非局所脱出を捕まえる 構文で、例外処理ではない罠。 これって純粋関数とReturn[]で記述できそうな気がしたけど、 純粋関数では Return[]使えないのね... Orz

つまり、f[arg_] := body;は、f := With[{arg = #1}, body];へ 書き換え可能では無いと...


2008-03-12 [長年日記]

_ [SAD]Execvpe[], Execvp[]実装

Execve[]へのフロントエンドとして Execvpe[]と Execvp[]を実装しました。

Execvp[file_, {argv___}, options___]は、 execvp(3)相当でファイル名と引数列を渡すと 必要ならPATH変数で指定された検索パスから外部コマンドを 探し出し、現状の環境変数を引き継いで Execve[]します。

Execvpe[file_, {argv___}, {env___}, options___]は、 Execvp[]に環境envを渡せるようにしたものです。

なんで、execvpe(3)が無いんだろう... (execve(2)は、PATHの自動検索は行わないのがポイント)

_ [SAD]BidirectionalPipe[]再実装

前々から、やろうとしていた BidirectionalPipe[]の High Level定義への 置き換えを実施しました。 これで、Fortranと Cの間の文字列受け渡し(null終端忘れてるとか...) などの問題や、execlp(3)を使っているのに、コマンド名以外の引数を 渡せない問題が解消されます。

新しいプロトタイプは、以下の通り。

BidirectionalPipe[file_String, {argv___String}, Options___]

オプションとしては、Execve[]へのオプション(ForceCloseOnExec, CloseStd) や、子プロセスのIDを受け取るための PID:>varオプション、 環境を渡すための Environments->{env___String}オプションが使えます。 デフォルトでは、呼び出し時点の環境全体が子プロセスへ渡されます。

例題

OpenRead["!ls -l /usr/include"]相当のことを BidirectionalPipe[]で書くと

{in, out} = BidirectionalPipe["/bin/ls", {"ls", "-l", "/usr/include"}, PID:>pid];
l = Table[If[s = Read[in, String]; s === EndOfFile, Break[], s], {Infinity}];
Close[in]; Close[out];
Wait4[pid];

と、なります。 注意すべきは、閉じるべきファイル記述子が送信/受信用の二つあること、 子プロセスの最後を看取ってやる必要があることです。 通信終了後に子プロセスが自発的に死なない場合やエラー等で 強制切断するときは、Kill[]でシグナルを送って親プロセスから 明示的に殺す必要があります。 (パイプを閉じれば、子プロセス側では 読み込みに対しては EOF、 書き込みに対しては SIGPIPEが発生するので、例外処理が正しく 実装されている場合は read/write発行時には死んでくれる筈ですが、 内部で無限ループしたりすると親プロセスが死ぬまで残留することに なるので、停止が期待できない場合にはやはり明示的に殺す必要があります。) また、Kill[]で明示的に殺した場合も Wait[]かWait4[]で 最後を看取らないとプロセステーブル上のリソースは開放されないので unix初心者は要注意。

_ [LHC]LHCb見学してきました

KEKから来た国際企画課長がLHCbを見学するのに同行しての LHCb見学。

解説は、LHCb Spokespersonの中田先生


2008-03-13 [長年日記]

_ [SAD][FreeBSD]gfortran 4.4.0で試験中

リンクに失敗、explシンボルが解決できない

ISO C99を調査中...C99で総称数学関数用に導入されたexp(3)の long double版のようだ...

FreeBSD 7-STABLEの libmにはまだ用意されていない Orz

CVS repositoryを捜索

math.hを見る限り explは CURRENTでも未実装 Orz

実装状況は、7-STABLEよりは進捗しており、sinl, coslなどが 実装されている。


2008-03-14 [長年日記]

_ [LHC]β解析ツールへの苦情

私の書いた、β-φ解析ツールが結果を出さないという苦情が舞い込む。

エラーコードを見ると、不正な入力データが原因、 エラーコードぐらい確認してほしいものである。 (なんのためにマニュアル書いたんだか Orz)

で、不正な入力データの正体は、入力に使われている LINX/Yファイルそのもの。 LINX/Yを読めるようにしろと要求されたときに渡されたサンプルと微妙に違う のが原因...だからインターフェースの仕様を文書でくれと言ったのに... Orz

通信で使うデータ構造の標準化を求めると「我々がスタンダードだ」とか 言っているし...

きちんと定義していないから解釈の相違で互換の無いファイルが作られ、 いちいちそれに対応するコストが発生していることはどう考えているのだろうか

_ [LHC]コントロール室へのコミッショニングアプリの導入について

コントロール室の計算機環境でdry-runを実施するという流れで、 やっと、その手の話が話題になるようになりました。

開発環境と運転環境が異なるので、 Software Configuration Management (SCM)が必要だと言う指摘に対しては、 確かに必要だと同意してくれたのですが、CVSの問題点やそれに対する 現代的な SCMシステムの利点を説明したが...新しいツールを覚えるのは 面倒と言うことでCVSで管理するつもりらしい

確かに、CVSも欠点を知った上できちんと運用出来るなら 問題無いのですが...関係者全員がその辺を理解しているとは 思えない Orz

_ [SAD]マニュアル追加

一般ユーザーの需要がありそうな amorita branch拡張を文書化

  • ListRandom[]
  • SeedRandom[]
  • Random[]ファミリー関数
  • Execvpe[], Execvp[]
  • BidirectionalPipe[]

2008-03-15 [長年日記]

_ [SAD]マニュアル追加

  • SigProcMask[]
  • SigPending[]
  • SigSuspend[]

多分、使う人は少なそう...

_ [SAD]さらにマニュアル追加

  • FeatureQ[]
  • BuildInfo[]
  • \$MessageLast

多分、一般ユーザーがお世話になるのは、障害解析時の BuildInfo[]ぐらい?

_ [SAD]将来の保守へ向けたタスクリスト

  • calc.y/bison.simple.f/yylex.f
    • bin/fbisonは、bisonのバージョンに依存していて、メンテしきれない
    • Fortranのフロントエンドを書き起こして、bison/yaccの出力をそのまま使うべきところ
  • WSPAC/PSPACコードのフロントエンド統一
    • SPACエンジンごとにフラグを新設するのは、美しくない
    • WSPACと PSPACを同時にオン出きるが、その結果に物理学的な意味があるとは思えない
    • フロントエンドの再実装のアイデア
      • SPACエンジンの使用を制御する単一のフラグ(RFSWみたいに...)
      • SPACエンジンの動的な組み込み
      • SPACエンジンの選択関数
      • SPACエンジン固有パラメータの設定インターフェース

SPACエンジンとトラッキングコード間の境界APIを定義し、明確に分離すれば 新しいエンジンの組み込みや試験が簡単になる。

calc.yに関しては、LLARパーサーフレームワークがもはや保守不能のため... bisonの出力を awk等で Fortranコードに加工するという発想は、 bisonの改良と共に出力形式が変化していく現状では無理がある。

_ [SAD][Fortran]GOTO文の使い方

gfortranなんかで SADをコンパイルしていると警告される構文として、 次のようなものがあります。

     integer :: i
     do i=1,5
        write(*,*)'before if: i=',i
        if(i .eq. 3)then
           goto 100
        endif
        write(*,*)'after  if: i=',i
100  enddo

何をやってるかといえば、DOループの途中で条件に依存してループの中身を GOTOで飛び越しています。

内容的には、END DO文に付いたラベルが、DOループの中なのか 外なのかが分かりにくいと言うものです。 少なくとも、END DO文を使うということは Fortran90を仮定することなので (多くの Fortran77コンパイラは拡張としてサポートしますが)、 GOTOの代わりに CYCLE文で、次の繰り返しに入る方がすっきりしたコードになります。

修正すべき箇所は何か所あるのかな... Orz

数えてみた...

正解は、61箇所


2008-03-16 [長年日記]

_ [SAD][Fortran]SADにおけるFortran I/Oの問題

SADInspectで、定義が長いシンボルを選択したときに 表示が更新されないことがあるので、調査していたのだが... Fortran I/Oのバッファリングが諸悪の根源のようです Orz

ネットワークからのストリーム受信を、非同期に実行するために Tkのハンドラから受信ルーチンを起動して n = SelectUnit[lun, 0]と Read[lun, {n * Byte}]の組み合わせで Non-blocking uni-byte stream inputを行っているのだが、 Read[]中に Fortran I/Oのバッファがリフィルされ kernel側のバッファが空かつ Fortran I/Oバッファが空でない 状態になると受信が停止します。 (kernel側バッファが空なので、ハンドラがトリガーされない & SelectUnit[]は 0を返すので読むべき量が分からない)


2008-03-17 [長年日記]

_ [FreeBSD]openoffice.orgがコンパイルできない件

原因判明

openoffice.orgには icu 3.6のソースが組み込まれており 自前でコンパイルして使っているのだが、portsが configure時にCPPFLAGSに渡している -I/usr/local/includeが自前のヘッダーへの パスよりも先に使われているために、 コンパイル時に ports/devel/icuでインストールされている icu 3.8.1のヘッダーが使用され icu 3.6のライブラリーとの リンクに失敗していました。

本来は、Makefile側を修正して-I/usr/local/includeの 優先順位を下げるべき所だが、面倒なので/usr/local/include/layout/usr/local/include/unicodeを一時的に名前を変えてごまかすことに

_ [Fortran]同一ファイルに対するOPEN文の挙動

同一の character device (/dev/null)を開くテスト

     character(len=32) :: fn

     fn='/dev/null'

     write(*,*)'Open10'
     open(10,file=fn,status='UNKNOWN')

     write(*,*)'Open11'
     open(11,file=fn,status='UNKNOWN')

     write(*,*)'Open12'
     open(12,file=fn,status='UNKNOWN')

     end
コンパイラOPEN動作
g95 0.91 20080220すべて成功
g77 3.4.6すべて成功
gfortran 4.2.4 20080305(prerelease)open(11,...)で失敗
gfortran 4.3.1 20080306(prerelease)open(11,...)で失敗
Intel Fortran 7.1open(11,...)で失敗
Intel Fortran 8.1すべて成功

同一のregular file(/tmp/fortran.txt)を開くテスト

     character(len=32) :: fn

     fn='/tmp/fortran.txt'

     write(*,*)'Open10'
     open(10,file=fn,status='UNKNOWN')

     write(*,*)'Open11'
     open(11,file=fn,status='UNKNOWN')

     write(*,*)'Open12'
     open(12,file=fn,status='UNKNOWN')

     read(12,'(a)')fn
     write(*,*)fn

     read(11,'(a)')fn
     write(*,*)fn

     end
コンパイラOPEN動作READ時のファイルポインタ
g95 0.91 20080220open(11,...)で失敗N/A
g77 3.4.6すべて成功独立
gfortran 4.2.4 20080305(prerelease)open(11,...)で失敗N/A
gfortran 4.3.1 20080306(prerelease)open(11,...)で失敗N/A
Intel Fortran 7.1open(11,...)で失敗N/A
Intel Fortran 8.1すべて成功独立

挙動のまとめ

  • gfortran 4.2/4.3と Interl Fortran 7.1は、同一ファイルの同時OPEN禁止
    • libgfortranを読む限り、既にOPEN済みのファイルとパス名とi-node番号が共に一致する場合は、OPENを拒否する
      • 同一パス名での i-node番号が異なる場合は問題ない(古いファイルが一度 unlinkされている場合など)
      • hard linkか VFS経由で同じファイルへ異なるパスでアクセスする場合も検査をすり抜ける
  • g77と Intel Fortran 8.1は、OPEN時に検査を行っていないと思われる
  • g95は、同一ファイルの同時OPENは原則禁止、device specialに関しては規則を緩めている
    • g95の libf95(io/unit.c, unix/unix_io.c)によれば、terminal device(character device)に対しての多重OPENを認めている

調査の範囲では、dup2(2)で上書きするための Logical Unit Numberを 確保するのに/dev/nullを多重OPENするという戦略は移植性が無い。

Intel Fortran 7.1から 8.1への挙動の変化が謎ではあるものの、 g77とことなり Fortran95規格ベースで実装されている gfortran/g95の挙動を 見る限り「同一ファイルへの多重OPENは禁止」は Fortran仕様的に何らかの根拠があると思われる。

_ [Fortran]SCRATCHなOPEN文の挙動

テストコード

     integer :: i

     write(*,*)'Open10'
     open(10,status='SCRATCH')

     write(*,*)'Open11'
     open(11,status='SCRATCH')

     write(*,*)'Open12'
     open(12,status='SCRATCH')

     do i=1,1000
        write(11,*)'New'
     enddo

     do i=1,10000000
        write(10,*)'Test'
     enddo

     end
コンパイラSCRATCHファイルの可視性SIGINT時の動作
g95 0.91 20080220不可視N/A
g77 3.4.6可視すべてのファイルが消える
gfortran 4.2.4 20080305(prerelease)不可視N/A
gfortran 4.3.1 20080306(prerelease)不可視N/A
Intel Fortran 7.1可視すべてのファイルが残る
Intel Fortran 8.1可視SIGINT時書き込み中のファイルが残る

挙動のまとめ

  • 一部の実装は、open(2)後にSCRATCHファイルをunlink(2)しない
  • SIGINT等で実行中断時に、SCRATCHファイルが残留する実装が存在する
    • シグナルハンドラが上書きされてる場合の動作が、不定(signal ->execve(2)な場合とか...)

調査の範囲では、dup2(2)で上書きするための Logical Unit Numberを 確保するのにSCRATCHファイルをOPENするという戦略では、 プロセス中断時に一時ファイルが残留する可能性がある。

つまり、一時ファイルがファイルシステムに残留する可能性や 多重OPEN禁止の実装まで考慮すると... OPEN文にmkstemp(3)とunlink(2)を組み合わせて 自前で実装するしか一般解が無いと言うことに...

_ [Fortran]OPEN文での/dev/nullの扱い

どうやら、gfortranに関しては/dev/null(正確にはisatty(3)が真となるもの stat(2)の結果、!S_ISREG()が真となるもの[訂正2008/03/18]) に対しては、unbufferedspecial_file[訂正2008/03/18]な 取扱いになり、regular fileと異なる振る舞いをする。

従って、dup2(2)で上書きするための Logic Unit Numberを 確保するのに/dev/nullOPENする代わりに regular fileOPENすると挙動が違うことに...

このために、mkstemp(3)とunlink(2)を組み合わせたitopenbuf_の 再実装はうまく動きませんでした。

パス名を新たに生成可能かつ、 isatty(3)が真になる!S_ISREG()が真になる[訂正2008/03/18]というと 使えそうなのは名前付きパイプかな?

とすると、mkdtemp(3) + mkfifo(2) + unlink(2) + rmdir(2)か...

_ [SAD][Fortran]itopenbuf_, itfopen*_の新実装

これまでの分析に基づいて、多重OPENの禁止処理にかからずに dup2(2)での上書き用の Logical Unit Numberを確保するコードを 実際に実装してみる。

有効にするには、sad.confへ以下を追加すること

USE_NEW_FORTRAN_OPEN_SIM=YES

動作は、/tmpopenbuf.で始まる 0700な一時 directoryを作って(mkdtemp(2))、 その中に名前付きパイプfifoを作成し(mkfifo(2))、 OPEN文で開いた後、 unlink(2)と rmdir(2)で後始末する。 一時ファイルの race conditionに対する安全性は、 mkdtemp(2)が予測不能な名前で ownerしかアクセスできない directoryを作ることに依存しています。

itfopenread_G77.fで実装されているOPEN文での DISP修飾のエミュレーションも unlink(2)で再実装する。 system経由の実装だと、/bin/shと/bin/rmを実行するために fork(2)とexecve(2)が2回づつ呼び出されるという パフォーマンス面での不利もあるが、 /bin/shを通過するためにシェルが解釈するメタ文字を含む パス名を正しく扱えない問題がありました。 (好き好んで、そんな変態的なパス名を一時ファイルに 使う上位層はいないはずですが...)

_ [LHC]β解析ツールが動かないという話

で呼ばれて、その場で調査してみる...

なんか、Union[]がエラー吐いてる...というか、その前の時点で データが入っていないのはおかしい....

あれ、なんかコードが違うような...って、これ古いコードじゃん Orz

まあ、エラーチャックに若干抜けがあったのも事実なのだが、 古いコードで新機能を呼び出せば動かないのは当たり前


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よりも少し早い?


2008-03-19 [長年日記]

_ [SAD]Trackingの謎

SADで RFSWRADONにしたTrackingを 実行するとTraclkingの中で実現する平衡分布が z方向へずれるという謎現象があるのですが、ヒントを得ました。

どんなヒントかといえば、トラッキングのために KEKBOpticsをロード(自動的にCALCが走る)した後、 事前にファイルに保存してある粒子分布を読み出し TrackParticles[]へ突っ込んだ場合(1)と、 その場で粒子分布を生成して TrackParticles[]へ突っ込んだ場合(2)で、 粒子分布の重心運動が異なるというものです。 (1)で事前に用意した粒子分布自体は、(2)で生成した 分布をファイルに書き出したものなわけで... File I/Oが破滅的にイカレてない限り粒子分布は 同じものになります。念のため、TrackParticles[]直前で 擬似乱数列も初期化しているので、プログラム的には まったく同じ出力を返すべきところですが、z方向に 30mm謎のドリフトをしてくれます。

注目すべきは、Opticsロードから TrackParticles[]開始までの 粒子分布生成の方法しか違わない点で、分布生成に Emittance[]の吐き出す座標変換行列を使っているので、 TrackParticles[]の直前に Emittance[]を差し込んだ所、 謎のドリフトが消失...トラッキングルーチンで Emittance[]が書き出す大域変数を参照している ようです。そんな仕様、聞いてないよ Orz

NORADの場合

NORADにした場合でも、謎のドリフトは発生する。


2008-03-20 [長年日記]

_ [SAD]calc.y修正

先日の日記で書いてた calc.y回りの保守を実施。

新しいコードでは、src/yylex_.c

  • Frotranから呼び出すyyparse_,yypushtoken_,yypoptoken_
  • calc.yから呼び出すトークンリーダーyylex

を実装し、calc.yからyaccにてcalc.hcalc.cを生成し そのまま使います。

yaccの出力を Cコンパイラに渡すために、calc.yのアクションは FortranからCへ書き換えて有ります。

calc.yの文法に関しては、 ";",")",ID型トークンによる exprの終端を 受け入れる(YYACCEPTする)構文に変更しています。 これは、calc.yが解析する構文が、部分構文で次のトークンが 構文定義に含まれないために、SADの MAINレベル的には正常な構文に対して 構文解析器が必ずsyntax errorで終了するという問題への修正です。

_ [SAD]itopenbuf_のデフォルトを変更

Revision 1500から USE_NEW_FORTRAN_OPEN_SIM=YESな状態が デフォルトになりました。

古い実装を使いたい場合は、USE_OLD_FORTRAN_OPEN_SIM=YESsad.confに追加してください。

_ [SAD]SPAC系フラグに関連するコード

なんか、SAPC系のフラグが乱立しているので、状況を整理してみる

  • PSPAC
    • tfsetparam.f(PSPAC*変数の読み込み)
    • tturn.f(tspac_ルーチンの呼び出し @ トラッキング)
  • WSPAC
    • track.f(WSPACフラグの初期化)
    • tturn.f(twspac_ルーチンの呼び出し @ トラッキング)
    • qtwiss.f(Space Charge付きのOptics計算)
    • temit.f(Space Charge付きのEmittance表示)
    • tintrb.f(Space Charge付きのEmittance計算)
  • SPAC
    • track.f(SPACフラグの初期化)
    • tturn.f(DRIFTエレメントに対してspdrift_を呼び出す)
    • tmulti.f(spkick_spapert_を呼び出す)
    • tsol.f(DRIFTエレメントに対してspdrift_を呼び出す)
    • tftrack.f(SPACフラグ付きの場合は、NPARAを殺している)

なお、Space Charge関連と思われるtspac.fにある tspac_ルーチンは、呼び出されない。

ざっと眺めた感じでは、次の問題がありそう

  • PSPACWSPACSPACは同時にオンに出来る
  • PSPACWSPACに関しては、NPARA>1の際にトラッキングが並列化される。
    • 並列実行時は、エレメント毎でのプロセス間同期は保証されないので、粒子間相互作用や、粒子分布の統計量を使う計算は「結果が保証できない」はず

2008-03-21 [長年日記]

_ [雑記]銀世界なCERN

ジュネーブに久々に雪が降りました。 市内の方は、芝生とかがうっすらと雪化粧をしている程度だったのですが、 CERNに近づくにつれて雪の厚みが増してゆく...

CERNは、一面銀世界でした。

_ [SAD]DynamicCall腐ってた

昔のMAIN Trunk(1.0.8.23.1bとか)に入っていた Christopher K. Allenの3D RMS Beam Envelope Simulationを 拡張モジュール形式に移植する作業を始めたのだが... DynamicCall[]の第二引数の取扱いが腐ってました。Orz

誰からも苦情が来なかったことからすると...誰も使って無いのかな?

_ [SAD]数学定数マクロ導入

どう考えても、piとかの数学定数がMACPHYS.incに有るのは おかしい気がするので、MACMATH.incを導入してみる。

コード中に散在している数学定数のうち一般的なものを これに収容して個別の定義を置き換える。 あと、pi関連の派生定数の名前も整理するべきかな?

pi2は、2*piのものとpi/2のものがある。 ちなみに、hpi = pi/2(Half Pi)は存在する。

さらに、pi4 = pi/4やpi2i = 2/pi (多分、pi2inverseの意)がある。

_ [SAD]calc.yバックポート

calc.y関連の再実装をバックポートする。

構文解析器がACCEPTする構文定義を変更しているので、 変更前のツリーにタグ(before_calc_y_update_20080321)を 打ち込んであります。

新しいコードで、LALR(1) parserが syntax errorを報告するようだと MAINへの入力が腐ってる可能性です。


2008-03-22 [長年日記]

_ [SAD]3D RMS Beam Envelope Simulationチューニング中

Christopher K. Allenの3D RMS Beam Envelope Simulation内で使われている Matrix Operatorの最適化といか再実装...

ざっと見たけど、MatrixFunctions.nは Fortran/C使いだった SAD初心者が書くコードですね。(私も、最初は似たようなコードを 書いた記憶が...) 行列演算が、ForループとPart演算子で記述されている。 これは書き直せば、絶対早くなると確信して作業開始。

結果、MatrixInnerProd2($L^2$ノルムな行列の内積)は、 リスト操作に直したらエラー処理込みで 3行に圧縮出来る上に、 速度は 17倍になった。また、MatrixNorm2[A]MatrixInnerProd2[A,A]で実装されているので、 Plus@@(Flatten[{A}]^2)に変えてみると約 30倍早くなる。 (倍率は、Random[6, 6]で作った 6x6の乱数行列に対するベンチマーク)

これらを使っているMatrixExpとか MatrixLogも 4〜5倍に高速化した。

ちなみに、MarixNorm2[A](すべての要素の2乗和)の実装だが、 Plus@@Flatten[{A^2}]よりもPlus@@(Flatten[{A}]^2)の方が 何割か早いのは、二重リストへの Power[]演算子よりも リニアなリストへの Power[]演算子の方が、ループ段数が少なく 結果を格納する一時オブジェクトの確保にかかるコストが少ないためと 思われる。

SADで速いコードを書こうとすると、後ろで動作している インタープリターの挙動を意識しなければならない点は、 初心者向きでは無いと思う。Mathematicaと言うか、Lisp的な言語なので 世に普及している手続き型言語とプログラムの組立てかたが異なるが、 関数言語的な思考が出来れば結構書きやすいのだが...

実行効率を求めるとバイトコンパイルや最適化をやらない インタープリターは、他の関数言語の実装に比べると不利だと思う (純粋関数言語なHaskellとかでは、ソースコードをコンパイルして 最適化するので、ものによっては Cで書くより速く動くらしぃ)

MatrixCommutatorとかは、行列積オペレータ(.)が使われており 小手先の改良を行う余地はなさそうなので、Cで実装する方向で... src/sim/sad_api.hとかに必要なプロトタイプを実装する


2008-03-23 [長年日記]

_ [LHC]なんか街中にマグネットが置いてあります

CERNの4月の一般公開(LHC運転前の最後一般公開になる予定)を 前に飾り付けが行われていますが、なんかLHCのマグネットを Meyrinの街中に飾っている模様。

Meyrinのバス通り沿いのロータリーには、Quadrupole Magnetが出現

MeryinのQ-Mag MeyrinのQ-Magアップ

また、CERNの Receptionから Rue de Meyrinを渡った向かい側の 球体状の建物の前には、Dipole Magnetが出現

CERN Receptionの向かい側

_ [SAD]スロットの罠

Mapに渡すために二つの行列の積を返す純関数を素直に

(#2.#1)&

と書いて、MapThreadに食わせてみたとこと、なぜか結果がおかしなことに...

演算結果を見る限り行列の要素毎の積になってるので、どうやら

(#2 #1)&

と解釈さているようです。何故... Orz

なんと、スロット演算子#に右結合するオペランドは実数らしい! つまり、最初の例では、(, #2., #1, ), &と 5個のトークンに分解されるようです。

対処としては、

((#2).#1)&

と書くか

(#2 . #1)&

のように明示的にwhitespaceを挿入すれば良いわけだが、 スロット演算子の意味付けから整数以外のものと結合する意味は 無いので、もう少し構文定義が改良できんものかねぇ

もっとも、SADの実装では構文定義から構文解析器を生成しているのではなく 直接構文解析器を書き下しているので、副作用が怖くて修正できん。 (この前の~演算子への修正で、予期しない構文定義への副作用が 発生していたのも、これが原因かと)

スロット演算子の実験

No入力SADの解釈結果
1(#1.6)&(#&)
2(#2.5e2)&(#25&)
3(#1.5.#2)&...#でプロンプト
4(#-1)&(-1+#)&
6(#0)&(#0&)
5(#0.5)&segmentation fault
  1. 小数部は切り捨てになる模様
  2. 実数が右結合してるのだから、ある意味当然の帰結
  3. 個人的には、1.5の次の.は実数の一部にはなれないのでトークンの区切りになり(,#1.5,.,#2,),&と分解されるのを期待していたのだが、謎な挙動である
  4. 負の実数は、正の実数リテラルに右結合-演算子であるが、左結合-演算子が優先するので、予想通りの動作
  5. これを、構文解析器がACCEPTするべきかは疑問の余地が...(後述)
  6. ちょっとまて、すくなくとも(#0)&と同じ解釈をすべきでない?

純関数(#0)&

f = (#0)&;

を定義して、f[]とかf[0]とかやってみる。 なにが返ってくるのだろう...わくわく

って、なにこの味気の無い出力

 In[1]:= f = (#0)&
Out[1]:= (#0&)
 In[2]:= f[]
???General::slot:  Undefined Slot #0 in (#0&)[]
???General::abort:  Aborted:
f[]
   ^
 ???-FFS-Error-?Undefined command or element: F[]
 In[2]:= f[0]
???General::slot:  Undefined Slot #0 in (#0&)[0]
???General::abort:  Aborted:
f[0]
    ^
 ???-FFS-Error-?Undefined command or element: F[0]
 In[2]:=

General::Slotで適用時にエラーにするくらいなら、 純関数オブジェクト生成時に構文エラーにすべきでない?

_ [SAD]3D RMS Beam Envelope Simulationの移植版公開

2005年にChristopher K. Allenが SAD V1.0.8.x向けに書いた 3D RMS Beam Envelope Simulationを Extension module形式にして移植しました。 移植に当たっては、MatrixFunctions.nをすべてCで再実装することで オリジナル版に比べ 例題の 実行速度は約5倍に高速化されています。

使い方とか中身の原理に関しては、 http://www-linac.kek.jp/seminar/allen.htmlを参照


2008-03-24 [長年日記]

_ [雑記]午後から雪が降り出す

午後になって降り出した雪がCERNから返る頃になったら積もっていました

CERNのバス停から Rue de Meyrin(ジュネーブ方面)を眺めるとこんな感じ

バス停から見た Rue de Meyrin


2008-03-25 [長年日記]

_ [SAD]SpaceCharge/Scheffの高速化

Scheff.n内の ScheffDecoup[], ScheffGenerator2[]を C moduleで再実装。 さらに、ScheffGenerator2[]を使った StepSigmaMatrix[]を StepSigmaMatrix2[]という名前で C moduleで再実装。 (もちろん、内部的なScheffGenerator2[]の呼び出しは C module内の 内部API経由)

これで、Revision 1569の実装に対して約 6倍に高速化(オリジナルからだと約 33倍)

SADScriptでのマトリクス演算が意外と遅いので(内部的に二重リストと Fortran配列間を相互変換するオーバーヘッドが大きいと思われる)、 ScheffPropElem[]も C moduleで実装すればもう少し速くなると 思われるが、可変刻みドライバーコードは変更容易性のために SADScriptのままにしておいた方が良いと思われるので、 手を付けずに残しておく。

_ [KEKB]停電からの復旧に20時間らしぃ

瞬停が原因でいろいろ止まったらしく、Belleの冷凍器が停止して 液体ヘリウムが飛んだらしく運転再開まで20時間ぐらいかかるそうだ

_ [SAD]スロット演算子

先日、スロットの罠で、スロット演算子#が 実数へ右結合するという書き方をしたが、どうやら本当に演算子らしいです。 { 2 3 } &は、二つの実数間に暗黙の積演算子が存在すると見做され {Times[2,3]}& -> ({6}&)と簡約されます。

それに対して、{ # 3 } &は、直感的には{Times[#, 3]}&と 解釈されそうな所なのですが、({#3}&)と簡約されます。

つまり、スロット演算子#は字句解析レベルでは独立したトークンであり、 構文解析レベルで右結合な演算子なのです。 つまり、字句解析レベルでは、#2という第2スロットを示す表現は、 スロット演算子#と実数リテラル2の2トークンだったのです。

さらに、スロット演算子の優先順位は暗黙の積演算子より高いことが分かります。

すると、次の疑問が沸き起こります。 スロット演算子と右結合したオペランドが実数リテラル以外の場合、何が起こる?

 In[1]:= f = {# a}&
Out[1]:= ({#a}&)
 In[2]:= a = 1
Out[2]:= 1
 In[3]:= g = {# a}&
Out[3]:= ({#a}&)
 In[4]:= f[1,2,3]
???FFS::undef:  Undefined element in ({#a}&)[1,2,3]
???General::abort:  Aborted:
f[1,2,3]
        ^
 ???-FFS-Error-?Undefined command or element: F[1
 In[4]:= g[1,2,3]
???FFS::undef:  Undefined element in ({#a}&)[1,2,3]
???General::abort:  Aborted:
g[1,2,3]
        ^
 ???-FFS-Error-?Undefined command or element: G[1
 In[4]:=

なんと、シンボルaと右結合するではありませんか!(fの拘束結果) これだけ見ると、純関数の参照するスロット番号を変数としてパラメータ化 出来そうなのですが、SADの実装ではそうは問屋が下ろしません。 不思議なことに実数1に拘束されたシンボルaに 右結合したスロット演算子の簡約結果が奇妙なことになっています(gの拘束結果)

つまり、スロット演算子#は右結合かつ Hold属性を 持っているようです。

ただ、fgを作用させた結果は、何とも味気ないものになっていまが、 発生しているエラーはUndefined Slotでは無いのでまだまな謎は尽きません。

怪しい構文定義

こうなってくると、スロット演算子##の動作です。 {## 2}&{## a}&は予想に違わず ({##2}&)({##a}&)に簡約されます。

さて、トークンレベルではどうなっているのでしょう?

{ # # }&の評価結果は、なんと({#}&)になります。 解釈に悩みますが、この挙動から

  • ##は字句解析レベルで一個の独立したトークンである
  • 2つのスロット演算子#の内、どちらかが構文解析で無視された

ことが分かります。 スロット演算子は、右結合かつオペランドが無い場合は暗黙のうちに 1をオペランドとするので、これまでの見てきた動作との 一貫性を優先するなら({#(#1)}&)のように評価されるべきところ だと思われます。少なくとも、勝手にトークンが失われるのは反則でしょう。

ここで、二つ目の#をカッコで括ったさらに怪しい構文を試してみます。

 In[1]:= f1 = { # (#) } &
Out[1]:= ({##}&)
 In[2]:= f2 = { ## }&
Out[2]:= ({##}&)
 In[3]:= f1@@Range[10]
???General::wrongtype:  Argument must be Number or symbol in ({##}&)[1,2,3,4,5,6,7,8,9,10]
???General::abort:  Aborted:
f1@@Range[10]
             ^
 ???-FFS-Error-?Undefined command or element: F1@@RANGE[10]
 In[3]:= f2@@Range[10]
Out[3]:= {1,2,3,4,5,6,7,8,9,10}
 In[4]:= f1===f2
Out[4]:= 0
 In[5]:=

すごく謎な挙動です、f2に拘束している純関数は、 すべての引数のリストを返す演算子で普通に動作していますが。 無理やりスロット演算子にスロット演算子を結合させた純関数(f1)は まともに動きません。

SameQは、f1f2の違いを認識しているようですが、 表示上区別が付きません。もしやと思い、ToString[]を試してみると...

 In[1]:= f1 = { # (#) }&
Out[1]:= ({##}&)
 In[2]:= f2 = { ## }&
Out[2]:= ({##}&)
 In[3]:= ToString[f1]
Out[3]:= "({##}&)"
 In[4]:= ToString[f2]
Out[4]:= "({##}&)"

これは、もはや笑うしか有りません。 つまり、環境と結合の無い純関数の定義を ToStringで シリアライズしたものをToExpressionで元通りに復元不能と 言うことです。


2008-03-26 [長年日記]

_ [SAD]SpaceCharge/Scheffの高速化の続き

もうそれほど速くはならないと思うがベンチマーク目的で、 ScheffPropElem[]とCompStepSize[]のC versionを試しに書いてみたところ...

なんかさらに2倍速になるんですけど Orz

やっぱり、SADインタープリターが致命的に遅いのかな...

KEKBで使ってる SADScriptで書いた Optics Correctionの計算とかも Cで書き直すと10倍ぐらい速くなりそうな気がしてきた

とすると、欲しくなるのは

  • SADScriptコンパイラー
    • SADScript関数の定義から、C/Fortran等のソースへコンパイルする
  • JIT付きSADScriptインタープリター
    • Just In Timeに関数をバイトコード変換して最適化して実行する

あたりですね。

前者に関しては、例えばC++上に SADインタプリター内のオブジェクトと 操作を表現するクラスを作って、変換時に型情報を追跡して 効率よくC++のコードへマップ出来れば、そこそこの性能は出そうです。

後者に関しては、バックエンドVMに LLVMとかが使えそうです。 上層で、関数言語的な簡約と最適化を行った後、LLVM向けの バイトコードを吐き出して、LLVMがローカルなマシンコードへ 最適化を行いつつ変換するみたいな実装とか...

どちらにしろ、SADScriptのメンテナンス性の良い構文解析器が必要な気がし ます。まずは、野菜作りですかね?(Yet Another SAD Interpreter)


2008-03-27 [長年日記]

_ [SAD][LLVM]LLVM-GCC

昔の日記に書いていた LLVM-GCCで SADがコンパイル出来ない件だが、どうやら llvm本体のバグか llvm-gfortranが複素数に対する累乗演算子を正しいバイトコードへ 変換出来ていないのが原因のようです。

状況としては、a**bにて aまたはbCOMPLEX型の ときに発生する模様。exp()とかlog()COMPLEX型に対しても 正常に動くようなので、a**bexp(b * log(a))へ書き直せば コンパイルは可能になりましたが、inimem_内でSegmentation Fault するようです。ilistrootを用いてSAD内のヒープ管理領域を初期化する 際に発生しているので、ilistを格納しているcommon blockの状態が おかしなことになっている模様。

リンカーが下記のような警告を出すので、アライメントも怪しい...

/usr/bin/ld: Warning: alignment 16 of symbol `ffs_' in libsad.a(tffs.o) is smaller than 32 in libsad.a(tffs.o)
/usr/bin/ld: Warning: alignment 16 of symbol `itparm_' in libsad.a(tpara.o) is smaller than 32 in libsad.a(tpara.o)
/usr/bin/ld: Warning: alignment 16 of symbol `mtfcommon_' in libsad.a(tfetok.o) is smaller than 32 in libsad.a(tfetok.o)
/usr/bin/ld: Warning: alignment 16 of symbol `rbufcom_' in libsad.a(tfreadbuf.o) is smaller than 32 in libsad.a(tfreadbuf.o)
/usr/bin/ld: Warning: alignment 16 of symbol `tffvp_' in libsad.a(track.o) is smaller than 32 in libsad.a(track.o)
/usr/bin/ld: Warning: alignment 16 of symbol `tok_' in libsad.a(tfetok.o) is smaller than 32 in libsad.a(tfetok.o)
本日のツッコミ(全1件) [ツッコミを入れる]

_ Y氏 [LLVMはiPhoneで使われているようですね。早く日本でも発売されないかなぁ...]


2008-03-28 [長年日記]

_ [雑記]今頃、日本では...

AsiaBSDCon 2008をやっている頃なんだろ〜な

そのうち、取材記事がMYCOMジャーナル辺りに上がるのを期待

_ [SAD]過去の変更記録調査のために

SAD本体のコードは20年選手なので、紆余曲折を経て謎コードに なっている部分を理解するには、古いコードを発掘して変更内容を 追跡することが必要になったりしますが、関連する変更箇所を探しながら 時間方向に遡る作業は CVS向きでは無いのでCVS repositoryを コピーしてきて調査用の Subversion repositoryを生成してみる。

ふむ、CVS repository上最古のコードは 1995年なのか... その時点で呼び出し元と呼び出し先で引数の数と型が 整合していない例を見たことがあるが、そこから遡る追跡調査は 至難の技かな

変更差分調査の意義

「ソースがドキュメントだ」とか「ソースにすべて書いてある」とか 言う人もいますが、下記の理由によりコードやデータ構造を理解するには インクリメンタルな変更差分から変更意図を類推する作業が必要です。

  • 内部のデータ構造/APIの仕様書とその改訂履歴が無い
  • 内部での大域的データ構造へのアクセスコードにMagic Numberが即値で埋められている
  • ソース上にコメント等の解説が無い、もしくはコードと同期していない
    • 複数のソースのコメント間に矛盾した記述が有る場合も...
    • 同一のデータ構造の取扱いにコード間で矛盾がある場合も...
  • CVS repositoryのコミットログに変更意図が記述されていないので変更差分から類推する必要がある
    • Version番号だけでは、変更意図が分かりません
    • 変更差分が、バグ入りで変更意図を反映していない場合も...

最近調査中のコード

コメントを読む限り、 src/inc/MACPHYS.incの echargには、 昔は elementary chargeがC単位で入っていたようなのですが、 途中からエネルギーの単位がJからeVに変更され echarg1になっているが、参照コードによっては 1.602176487x 10^-19 Cであることを期待しているものが 見受けられる。

同じ物理定数が異なる名前で、複数箇所で定義されている。 光速cや真空の透磁率$\mu_0$のように定義値に なってるものはまだ良いが、観測量なものに関しては複数箇所で 定義するのは保守性の悪化を招く。 (kg(シリコン単結晶の真球を使ってアボガドロ数を定義値にして定める)か J(ホール効果等からプランク定数hを定義値にして定める)を定義値に するって話は出てるけど、置き換えまだ〜)

事実、収録元か収録時期が異なる観測量な物理定数が存在する。 また、こうした定数は 2003年から更新されていない。

_ [雑記]最近、暗くなるのが遅い

流石に 7時半を回ると真っ暗ですが、 7時だとまだ明るい。

ついに、明るいうちに店がしまる季節到来 Orz


2008-03-29 [長年日記]

_ [SAD][LLVM]SAD on LLVM-GCC

27日の日記でLLVM-GCCを使ってコンパイルしたSADだが、 common block回りの不具合原因が判明。

ここで問題です、次の Fortranコードを llvm-gfrotranで コンパイルした場合、どんな結果が出力されるでしょう?

     implicit none
     integer*4 i
     logical*4 flags(64),flag1,flag2,flag3
     common /tflags/flags
     equivalence (flag2,flags(2))
     equivalence (flag3,flags(3))
     do i=1,64
        flags(i)=.false.
     enddo

     write(*,*)'Clear:'
     write(*,*)'flags(1)=',flags(1)
     write(*,*)'flag1=',flag1
     write(*,*)'flags(2)=',flags(2)
     write(*,*)'flag2=',flag2
     write(*,*)'flags(3)=',flags(3)
     write(*,*)'flag3=',flag3

     flag2=.true.

     write(*,*)'After: flag2=.true.'
     write(*,*)'flags(1)=',flags(1)
     write(*,*)'flag1=',flag1
     write(*,*)'flags(2)=',flags(2)
     write(*,*)'flag2=',flag2
     write(*,*)'flags(3)=',flags(3)
     write(*,*)'flag3=',flag3

     do i=1,64
        flags(i)=.false.
     enddo

     write(*,*)'Clear:'
     write(*,*)'flags(1)=',flags(1)
     write(*,*)'flag1=',flag1
     write(*,*)'flags(2)=',flags(2)
     write(*,*)'flag2=',flag2
     write(*,*)'flags(3)=',flags(3)
     write(*,*)'flag3=',flag3

     flags(1)=.true.

     write(*,*)'After: flags(1)=.true.'
     write(*,*)'flags(1)=',flags(1)
     write(*,*)'flag1=',flag1
     write(*,*)'flags(2)=',flags(2)
     write(*,*)'flag2=',flag2
     write(*,*)'flags(3)=',flags(3)
     write(*,*)'flag3=',flag3

     flag1=.false.

     write(*,*)'After: flag1=.false.'
     write(*,*)'flags(1)=',flags(1)
     write(*,*)'flag1=',flag1
     write(*,*)'flags(2)=',flags(2)
     write(*,*)'flag2=',flag2
     write(*,*)'flags(3)=',flags(3)
     write(*,*)'flag3=',flag3

     end

Subversion resporitory revision 48818での結果は、以下の通り。

Clear:
flags(1)= F
flag1= F
flags(2)= F
flag2= F
flags(3)= F
flag3= F
After: flag2=.true.
flags(1)= T
flag1= F
flags(2)= F
flag2= T
flags(3)= F
flag3= T
Clear:
flags(1)= F
flag1= F
flags(2)= F
flag2= F
flags(3)= F
flag3= F
After: flags(1)=.true.
flags(1)= T
flag1= F
flags(2)= F
flag2= T
flags(3)= F
flag3= T
After: flag1=.false.
flags(1)= T
flag1= F
flags(2)= F
flag2= T
flags(3)= F
flag3= T

要するに、EQUIVALENCE文に配列を添字付きで与えた場合、 添字の部分が無視されているようです。

バグ 1971でも EQUIVALENCEの不具合が報告されている模様です。

SADは、common blockEQUIVALENCEを多用してるので このバグが直らない限り、LLVM-GCCを使うのは絶望的です。

_ [SAD]CVS repository考古学

SADの CVS repositoryから調査用に変換生成した Subversion repositoryを あさってみると...

  • 現在の CVS repositoryは1995/09/13に初期化された
    • SADの開発は、1986年ごろに始まっている
  • CVS repositoryに実際にコミットしたことのあるコミッターは、9
    • 最多コミッターのコミット数は、全体の66.9%を占める。
    • コミット数は、第一位から66.9%,13.7%,12.2%で上位3コミッターが全体の92.8%を占める(コミット数なので、コード行数ではないことに注意)
  • CVS repository上のコードで、始めて動作したものは 1995/09/15と思われる(コミットメッセージは、working Alpha version 1.0)
  • src/MAIN.fへ Version番号が格納されるようになったのは1997/02/06、最初のVersion番号は1.0.1bである。

といったことが、分かりました。

開発形態は、少数精鋭による典型的な伽藍モデルのようです。

あとは、CVS repository導入直後から現代までのコード行数の変遷でも 調べて見るべきか?

本日のツッコミ(全1件) [ツッコミを入れる]

_ Y氏 [バグ1971は直ったようですね。]


2008-03-30 [長年日記]

_ [雑記]本日よりサマータイム突入

3月最終日曜日となる本日午前1時からサマータイムへ突入しました。

現在の日本との時差は7時間です。

街中の一部の時計は、サマータイム突入前の時刻を指しているものが 見受けられる所を見ると、切り替えは自動ではない模様。

_ [SAD]スロットバグの修正

前にスロットの罠で報告した(#0.5)&segmentation faultになる件だが、原因が分かったので修正した。

実は、スロット関数を使った表現Slot[0.5]&では、問題なく 受け入れられるのだが、この違いは、スロット演算子をsrc/tfeexpr.f経由で スロット関数に変換する過程で不正な参照を持ったスロット関数を 生成していることが原因でした。 また、表示はスロット演算子形式になるので、ToString[]して ToExpression[]すると問題が発生する罠。

詳細は、Ticket-11を 参照のこと。

_ [SAD]数値リテラルのトークン化の仕様修正

前にスロットの罠で報告した(#1.5.#2)&...#でプロンプト待ちになる件だが、原因が分かりました。

tfetok()の返すトークンを追跡したところ、#の次のトークンは 1で始まるので数値リテラルをトークン化する eval1()が 呼び出されるが、このサブルーチン何を思ったかトークン中に 2個目の.が出現するとそのままリターンしてしまいます。 したがって、#の次のトークンが謎文字列1.5.#2になることに...

eval1().で開始する実数リテラルをサポートするようなので、 この2個目の.を検知してアボートするロジックは、 RepeatedNull(..),Repeated(...)演算子を 見つけた際に実数リテラルとしてトークン化せずに上位ロジックに 制御を戻すためのものと思われますが、.の連続性を 検査していないので誤爆している模様です。

現在の実装の挙動はおかしいので仕様レベルの修正をRevision 1658で入れました。

具体的には、連続する.(つまり..)を見つけたら その直前で実数リテラルが終了するものと解釈します。 したがって、..で開始する文字列は実数リテラル部の長さが0と なるのでm=0を返して終了。 .を含む実数リテラルに.が継続した形2.5.は、 2.5までが実数リテラルとして解釈され、続く.は次のトークンの 開始文字になります。 また、.を含まない実数リテラルに..が継続した形12..は、 実数リテラル12と継続文字列..に分割されます。 なお、.の後に[^.eEdD0-9]が継続する場合は、.までが 実数リテラルとして解釈されるので、(2.A)(, 2., A, )とトークン化され、Times[2., A]と解釈されます。

SADには正規の文法定義な存在していないので、バグと言うのも微妙なのですが、 標準的な表現には影響しないはずです。

ただし、ToString[]がコンソールへのエコーバックで使われる短縮形では、 各リテラルの短縮表現と後続リテラルの短縮表現を結合した際に生じる 文法的な曖昧性を考慮しないので、変換ToExpression[ToString[#]]&が 恒等変換で無いのは注意が必要です。

たとえば、(#2.0.#3)&Dot[#2.0, #3]&と解釈されますが、 ToString[]の結果は短縮表現((#2.#3)&)となり、 これをToExpression[]で解釈するとTimes[#2., #3]&と解釈されて しまいます。


2008-03-31 [長年日記]

_ [SAD]CVS MAIN trunkへのコミット数の推移

1995/09/13(CVS repositoryの初期化)から2008/03/26までの 各コミッターによるCVS MAIN trunkへのコミット数の推移 (branchへのコミットは除外)

Acct. 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008Total
A 75 81 250 449 293 228 224 164 60 111 61 31 64 29 2120
B 0 0 0 0 0 0 0 53 85 40 26 53 103 75 435
C 0 0 49 148 118 71 1 0 0 0 0 0 0 0 387
D 23 26 22 2 7 5 3 1 0 0 6 0 0 0 95
E 0 2 13 5 16 22 2 25 5 1 0 0 0 0 91
F 0 0 0 0 0 0 4 6 0 0 0 12 0 0 22
G 0 0 0 0 0 0 0 0 1 0 0 5 0 0 6
H 0 0 0 0 0 0 0 0 1 4 0 0 0 1 6
I 0 0 0 0 0 0 0 0 0 0 5 0 0 0 5
Total 98 109 334 604 434 326 234 249 152 156 98 101 167 105 3167

_ [LHC]β測定ツールの実働環境でのテスト

本日コントロールルームの環境とSPSの実測データを用いた β測定ツールの実働テストが行われました。

取り合えず、画面表示上の問題(ヒストグラムが線分で結ばれてるとか)とか データの受け渡し等で構成モジュールのバージョン違いが原因と思われる 問題が出たものの無事完了。

オンラインモデルと連携関連は時間切れで次回のテストに持ち越し?


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