昔の最近の出来事(2015.05)

2015/05/31

AM中に起床。

掃除したり、もそもそとコーディングしたり。

やっとPMXファイルのモデル部分だけを直接表示できるようになったのですが、 あるデータだけ 頂点法線の向きが反転しているような気がしたり。 ただ、ライトを使わずにレンダリングすれば、どのデータもそれっぽくなるので 頂点法線はあまり重要ではないような気も?

西川善司の3Dゲームファンのための「WITCH CHAPTER 0 [cry]」講座」。 次の世代のゲーム機でもしかすると普通に使われるようになるかも知れない話。 この記事の中でAGNIモデルのポリゴン数について、 「全体で約1,100万で、内訳は顔面、身体、アクセサリーなどで300万、毛髪で600万、 AGNIが着用している鳥の羽製ファードレスが約200万だ。」という一文 があったのですが、毛髪600万ポリゴン相当ってなんで?とちょっと 驚いたり。髪の毛は曲線で一本ずつ描画しているらしいのですが、 実際の人の髪の毛の本数は10万本と言われていて、一本あたりの制御点を 多目に見ても600万ポリゴン相当になるか?と思ったりも。

それにしても、以前、hairmakerと POV-Rayを使って10万本の髪の毛をレンダリングした時は使用するメモリ量とか ハンパない感じだったのですが、次世代のゲーム機に搭載されるメモリ量は どいう事になるんだろうか?と思ったりも。

2015/05/30

起きたら午後もいい時間。寝すぎ。

diff-modeもう少しだけ。一つのhunkの中に複数の差分ブロックがあると、 ブロックの数だけ子プロセスでdiffを実行するようです。

***************
*** 4077,4094 ****

  2011-06-21  Leo Liu  <sdl.web@gmail.com>

! 	* m4/sha256.m4:
! 	* m4/sha512.m4:
  	* m4/gl-comp.m4:
  	* lib/u64.h:
! 	* lib/sha256.c:
! 	* lib/sha256.h:
! 	* lib/sha512.c:
! 	* lib/sha512.h:
  	* lib/makefile.w32-in (GNULIBOBJS):
  	* lib/gnulib.mk:
! 	* Makefile.in (GNULIB_MODULES): Add crypto/sha256 and
! 	crypto/sha512 modules from gnulib.

  2011-06-19  Paul Eggert  <eggert@cs.ucla.edu>

--- 4077,4094 ----

  2011-06-21  Leo Liu  <sdl.web@gmail.com>

! 	* m4/Sha256.m4:
! 	* m4/Sha512.m4:
  	* m4/gl-comp.m4:
  	* lib/u64.h:
! 	* lib/Sha256.c:
! 	* lib/Sha256.h:
! 	* lib/Sha512.c:
! 	* lib/Sha512.h:
  	* lib/makefile.w32-in (GNULIBOBJS):
  	* lib/gnulib.mk:
! 	* Makefile.in (GNULIB_MODULES): Add crypto/Sha256 and
! 	crypto/Sha512 modules from gnulib.

  2011-06-19  Paul Eggert  <eggert@cs.ucla.edu>


上の例だと、三つのブロックがあるという数え方になります。 一つのhunkの中にストライプ状に沢山の差分ブロックがある (例えば1行おきに差分があるとか)場合に一番時間がかかる 事になるようです。

ちょろりお出かけ。コンビニで買い物してたら地震が。 「酒瓶が倒れないようにおさえて!」と店長ぽい人が店員に 指示してたり。やたら酒瓶の心配をしてたのですが、 そんなに倒れやすいものなのだろうか?

2015/05/29

遅めに帰着。

CygwinのEmacsでdiff-modeが遅い件。なんとなく理由は判ったような。 diff-refine-hunkの中でsmerge-refine-substという関数を実行して いるのですがこれが本体です。で、この中では時間のかかる要素が 大きく二つあるようです。 一つはsmerge-refine-chopup-regionという関数を二回実行して 二つのテンポラリファイルを生成する部分。もう一つは diffを子プロセス実行して前述二つのファイルの差分を取る部分。 それぞれ約0.15秒ずつかかって合計で約0.3秒になるという感じ。 Cygwinじゃ(というかWindowsじゃ)遅くにしかならないと思います。 てか何故こんな事やってるんだ?というのが正直な感想。

diffの結果自体はdiff-modeに入った時点で得られています。 この時、diff-hunk-nextを実行すると文字単位の差分が強調表示 される訳ですが、これはdiff-modeのバッファ上で得ているもの だと思っていました。ここが先日「Cygwinだと遅くなる要素がある 箇所には思えない」と書いた理由です。 ところが、実際には 変更前と変更後の文字列を ワード単位に区切って二つのファイルを生成して、それらのdiffを 取る事で文字単位(正確にはワード単位)の差分を得ているようです。 なんかこれ、自前の差分抽出コードを実行した方がずっと速いように 思うのですが、そうはなっていないようです。 CPUがいくら速くなっても無駄に時間のかかる処理をしてるんじゃ ちっともうれしく無いなぁと思ったりも。

2015/05/28

遅めに帰着。

CygwinのEmacsでediffやvc-modeのdiffを使っていると、nとかpでhunkを移動するのが なんだかとても遅い(一つ移動するのに数秒を要する場合がある)気がしていたのですが、 こんなもんかな?と思って使ってました。 ふとFedoraの方で試してみたところ、全くつっかかる事無くhunk移動ができるので、 なんでだ?と思ったり。
何かしらCPUパワーを使いながら完全に固まる感じの重さなので、どこかで無駄に 時間がかかっているものと思われるのですがどうやって調べたもんか。 因みに -Qで立ち上げても重いので、自分の設定が影響している感じでは無さそう。

diff-modeで、diff-hunk-nextが次のhunkに移動する関数なのですが、 どういう事をやってるのだろう?と実体を見ようとしたところ、関数定義が どこにも見当たらなかったり。

$ grep -r diff-hunk-next .
./doc/emacs/files.texi:@findex diff-hunk-next
./doc/emacs/files.texi:Move to the next hunk-start (@code{diff-hunk-next}).
./info/emacs.info:     Move to the next hunk-start (‘diff-hunk-next’).
./info/emacs.info:* diff-hunk-next:                        Diff Mode.           (line  33)
./lisp/ChangeLog.11:    * diff-mode.el (diff-hunk-prev, diff-hunk-next):
./lisp/vc/diff-mode.el:  '(("n" . diff-hunk-next)
./lisp/vc/diff-mode.el:    ("\t" . diff-hunk-next)
./lisp/vc/diff-mode.el:    ["Next Hunk"         diff-hunk-next
./lisp/vc/diff-mode.el:       (diff-hunk-next)
./lisp/vc/diff-mode.el:                          (= (progn (diff-hunk-next) (point))
./lisp/vc/diff-mode.el:  (diff-hunk-next arg)
./lisp/vc/diff-mode.el: (diff-hunk-next))))))
./lisp/vc/diff-mode.el:                 (diff-hunk-next)
./lisp/vc/diff-mode.el:      ;; When there's no more hunks, diff-hunk-next signals an error.
バイナリファイル ./lisp/vc/diff-mode.elc に一致しました

helpで調べてみると、diff-mode.elの中でeasy-mmode-define-navigation とやらを使って定義されている模様。

diff-auto-refine-modeをdisableにしてみると突っかかりが無くなる 所から、これが関係しているが判りました。とは言え、 diff-auto-refine-modeをdisableにしてしまうと、折角の差分箇所の 色付けが行われなくなります。この中で何に時間を食っているのかを 調べてみるのが良さそう。

diff-refine-hunkで時間がかかっている所までは判りましたが 中身はまだ観察できず。それにしても Cygwinだと遅くなる要素がある 箇所には思えないのですが、何が影響するのだろう?と疑問に思ったり。 因みに、Cygwinではdiff-refine-hunkの実行に0.3秒くらいかかる 様ですが、VMware上のFedoraのEmacsで動かしたのでは 0.003秒くらい しかかかっておらず、Cygwinのは100倍遅いという感じです。 てか、0.3秒(速い場合でこれ)はいくらなんでも遅すぎだと思います。

2015/05/27

早くも無く遅くも無く。

そういえばJavaのランタイムをアップデートしたのですが、 Web公開しているCinderella で作成した図を表示するのに、いちいち例外サイトリストで 指定しなくてはならなかったり。また、大分前からローカルファイルで アップレット表示するのも上手く動かなくなってました。 そんな訳で、随分前に作成した 「HSVホイールを作ったときの話」 にアップレット実行についての留意点を追記してみたり。御参考まで。

2015/05/26

遅めに帰着。

Web巡回して終了。

2015/05/25

遅めに帰着。

Emacs突然死問題。テストで立ち上げている方は死なず、後から立ち上げて 普段使いしている方が死ぬという状況。むしろ死なない方の理由が判らない。

2015/05/24

AM中に起床。関東地方も雨が降るって予報だったけど雨雲は ギリギリ陸地に到達していない模様。

Emacs突然死問題。結局debug版は22時間ほど美人時計等を動かしっぱなし にしても死ななかったり。そのまま起動継続。

洗濯したり掃除したり。

Emacs突然死問題。テストで立ち上げている方は36時間ほど動き続けて いるのですが、後で立ち上げた同じバイナリを普段使いで使っていると 12時間程度で死んだり。という訳でfork()とvfork()の違いはあまり関係 無さそう。うーむ。

もそもそとコーディング。あまり捗らず。

2015/05/23

AM中に起床。

Emacs突然死問題。子プロセス実行が突然死のトリガになっているという 推測から、vfork()を実行している箇所で少しモニタリングしてみる事に したり。すると、起動時に何やら子プロセスが起動されているのを知ったり。

callproc.c fork() pid=6576  /usr/bin/ssh
callproc.c fork() pid=0  /usr/bin/ssh
callproc.c fork() pid=13928  /usr/bin/ssh
callproc.c fork() pid=0  /usr/bin/ssh
callproc.c fork() pid=9564  /usr/bin/ssh
callproc.c fork() pid=0  /usr/bin/ssh
callproc.c fork() pid=9716  /bin/tar
callproc.c fork() pid=0  /bin/tar
callproc.c fork() pid=10372  /bin/gpg
callproc.c fork() pid=0  /bin/gpg

何の目的で実行しているかまでは判りませんが、/bin/tarは流石に 「何故?」と思ったりも。

あと、vfork()をfork()に変えてみたり。Cygwinではfork()とvfork()は 同じ物らしいのですが、関係無いよねという確認&関係していたとして 落ちなくなればラッキー という訳で試してみる事にしてみました。

調査用のEmacsで普通にやりそうな操作をちょろっと試してみたところ、 ファイルを開く度に/bin/gitを実行している事が判ったり。何やら 預かり知らない所で色々動かしているなぁ?と思ったりも。

ちょろりお出かけ。そういやATMでリロードした時、カードを入れて、 パスワードを入れて、金額を入れる訳ですが、機械がお札を勘定している と思われるタイミングでパスワードが違っているという旨のメニュー が表示されたり。無意識だったので何か間違えたのだろうとは 思いますが、パスワードが違っているのにも関わらず、先行して 取引手続きを開始するのは前倒し過ぎないか?と思ったりも。 まぁ、混雑時のスループットを上げる目的があるのだろうと思いますし、 実質問題は無いとは思いますが、フィッシングっぽい動きが気持ち 悪いです。

もそもそとコーディング。

2015/05/22

早めに帰着。

TVを観ていたらあまりの眠さに急速停止。

2015/05/21

遅めに帰着。

Cygwin2.0にしてからEmacs-w32が死に易くなった気がする件。 トリガの一旦を担っているのが美人時計による子プロセス実行だと いうのはこれまでの状況から目星は付いていて、実際、美人時計を 動かさず(emnekoと世界時計だけならば)に使っている分には ここ2日間(夜中と昼間はWindows自体をスリープにしているので、 実質半日程度の稼動時間ですが)では死んでいません。
では美人時計だけだとどうか?と試していたのですが、こちらも 死なず。なんてこった。美人時計を動かしながら編集作業をしてると 死ぬのだとすれば最悪パターンなのですが.....

2015/05/20

遅めに帰着。

あまりの眠さに急速停止。

2015/05/19

遅めに帰着。

ちょろり調べ事。

2015/05/18

遅めに帰着。

ちょろりコーディング。

2015/05/17

AM中に起床。

洗濯したり掃除したり。

PMX。ボーンは沢山パラメータがあってもう何が何やら。 頂点をパースした時には意味が判らなかったのですが、頂点毎にどのボーンの影響を 受けるかの情報が含まれている事が判ったり。

PMXは 各種インデックスのサイズがデータ毎に可変 (例えば頂点数が256個以下なら頂点インデックスはubyte、257個以上かつ65536個以下 なら頂点インデックスはushortのような感じ)なため、ファイルの読み込みが まぁまぁ面倒臭い構造になってます。 D言語では、ある型の配列を違う型の配列にキャストすると事故が起こりそうなので なんか嫌な感じです。

一週間ちょっとにCygwinを2.0に移行したのですが、 Emacsが少し死に易くなったような。大抵ほったらかしている間に死ぬのですが、 一度だけ編集真っ最中に死んだことがあってイマイチです。 やっぱりCygwinのアップデートに連動しているようで、この日より 前は突然死んだりすることは無かったのですが、何が関係しているのかよく判りません。

2015/05/16

AM中に起床。

録画消化したり、もそもそとコーディングしたり。

pmx_load_test

PMXフォーマットを表示してみたり。と言っても、モデル部分を一旦WavefrontのOBJ 形式にしてそれを表示するという感じですが(^^;
色々な部分が逆になってて(Zの方向が逆、それに伴う面の法線も逆、 TGAのY軸格納方向が逆、TGAの色要素の並びが逆、.....)、なかなかうまくいきませんでした。 ボーン部分は まだフォーマットがよく理解出来てません(^^;;;

2015/05/15

遅めに帰着。

調べ事をして終了。

2015/05/14

遅めに帰着。

おや?美人時計の画像がいつもと違っているような。

もそもそと思い出し。突っかかっていた箇所を思い出した。

2015/05/13

遅めに帰着。

あまりの眠さに急速停止。

2015/05/12

早くも無く遅くも無く。タイミングが悪く雨足が強くてずぶ濡れ。

Web巡回して終了。

2015/05/11

遅めに帰着。

放置していたコードを掘り起こして何やってたか思い出し。

2015/05/10

AM中に起床。掃除したり。

ぐうたら過ごして終了。

2015/05/09

AM中に起床。

そういえば少し不思議に思った事。Yahooの知恵袋って質問サイトが ありますが、あれの回答で「よく知りませんが.....」で始まる 回答をするのはなんで?と思ったり。 知っているつもりで間違えた回答をしているのでもなく、 知らない可能性があるにも係わらず名指しで回答を依頼された訳でも無いのに、 「よく知りませんが...」で自発的に回答できるのは、なんか(色々な意味で) スゲェと思えます。

gdcデータ化けの件。Fedoraで以前ビルドした dmd2.065+gcc-4.9.2のgdc ならば大丈夫そうだったので、 今年の初めにCygwinでビルドした時 に使ったソースに、先日のパッチを当てて ビルドしてみる事に。 結果、イケました(^^)v という訳で少なくとも2.065→2.066.1の間でエンバグしているのは確か なようですが、範囲が広すぎて(2.065と2.066.1とではlibphobosの作りも 大分違う)どこでどうエンバグしているかまでは判らず。

$ i686-pc-mingw32-gdc -g -frelease -O0 test_struct.d

$ ./a.exe
1: Vec3D(0.8, 0, 0, nan)
xyz=(0.800000 0.000000 0.000000) Vec3D(0.8, 0, 0, nan)
xyz=(0.800000 0.000000 0.000000) Vec3D(0.8, 0, 0, nan)
d=0.800000
2: Vec3D(1, 0, 0, nan)

$ i686-pc-mingw32-gdc -g -frelease -v
Using built-in specs.
COLLECT_GCC=i686-pc-mingw32-gdc
COLLECT_LTO_WRAPPER=/usr/local/gdc031_2065_492_mingwcross/libexec/gcc/i686-pc-mingw32/4.9.2/lto-wrapper.exe
Target: i686-pc-mingw32
Configured with: ../gcc-4.9.2/configure --with-pkgversion='gdc-4 c58d2e01d8' --build=i686-pc-cygwin --host=i686-pc-cygwin --target=i686-pc-mingw32 --enable-languages=d --prefix=/usr/local/gdc031_2065_492_mingwcross --with-sysroot=/usr/i686-pc-mingw32/sys-root --enable-threads --disable-nls --enable-sjlj-exceptions --disable-bootstrap
Thread model: win32
gcc version 4.9.2 (gdc-4 c58d2e01d8)

関数呼び出しの問題が無ければ 1年くらい前から使えてたであろうと 考えるとなんかちょっと複雑な心境です。

手持ちコードを一通りビルドテストした所、簡単なテストをした範囲では 大丈夫そう(いきなりSegfaultしたりはしない)。

という訳でMinGW-gdcのビルドでハマった箇所の覚書き。


はgdc本体がバグ修正される事を期待。その他、細かいのは色々あり。


今後、「★今の所 直し方不明」の問題にぶつかると、またしばらく新しいのは 使えない感じになります。
GDC本家では DMD2.067のマージ作業 が進められている所ですが、直し方不明の物が(そうでない物も)直ってくれる事を 期待したいです。ただ、結構派手に直しているようなので、2.067のマージが終わった 直後は安定しない可能性が高いかも知れません。

2015/05/08

遅めに帰着。

Cygwin2.0に移行。ひとまず問題は無さげ。

2015/05/07

遅めに帰着。

ちょろり実験。

2015/05/06

ゴミ捨ての為にAM中に起床。

値化け調査。あるメソッド内でのsqrt()の結果が変っぽいのですが、 メソッドの外で試してみる感じではうまく動いているような。

データ化けの現場を捉えたり。最小コードでは以下のような感じ。

$ cat -n test_struct.d
     1  import std.stdio;
     2  import std.math;
     3
     4  struct Vec3D
     5  {
     6    double x,y,z,w ;
     7
     8    void set(double x, double y, double z){
     9      this.x = x ;
    10      this.y = y ;
    11      this.z = z ;
    12    }
    13
    14    Vec3D normalize(){
    15      Vec3D retvec ;
    16      double d ;
    17      writef("xyz=(%f %f %f) %s\n", this.x, this.y, this.z, this) ;
    18      d=sqrt( this.x*this.x + this.y*this.y + this.z*this.z ) ;
    19      writef("d=%f\n",d) ;
    20      if( d>0.0 ){
    21        retvec.x = this.x/d ;
    22        retvec.y = this.y/d ;
    23        retvec.z = this.z/d ;
    24      }else{
    25        retvec.x = 0.1 ;
    26        retvec.y = 0.2 ;
    27        retvec.z = 0.3 ;
    28      }
    29      return(retvec) ;
    30    }
    31  }
    32
    33  void main()
    34  {
    35    Vec3D v ;
    36    v.set(0.8,0.0,0.0) ;
    37    writef("1: %s\n",v) ;
    38    v=v.normalize() ;
    39    writef("2: %s\n",v) ;
    40
    41    return ;
    42  }

$ i686-pc-mingw32-gdc -g -frelease -O0 test_struct.d

$ ./a.exe
1: Vec3D(0.8, 0, 0, nan)
xyz=(nan nan nan) Vec3D(nan, nan, nan, nan)
d=nan
2: Vec3D(0.1, 0.2, 0.3, nan)

36行目で構造体の初期値を設定した後、37行目で値が正しく表示 されてますが、38行目で正規化のメンバー関数を実行して入って 直ぐのところで、this が全てnanになってしまってます。 結果、sqrtの結果がnan、d>0.0が成立せず25〜27行目の デバッグ値が38行目で返っている感じになってます。
オリジナルのdmd 2.066.1での結果は以下の通り。

$ ../dmd/dmd_2.066.1/windows/bin/dmd.exe test_struct.d

$ ./test_struct.exe
1: Vec3D(0.8, 0, 0, nan)
xyz=(0.800000 0.000000 0.000000) Vec3D(0.8, 0, 0, nan)
d=0.800000
2: Vec3D(1, 0, 0, nan)

まぁ、そうなるわな。

問題箇所はnormalize()の最初の方でthis値が化けてしまっている 所。デバッガでステップ実行してみると、以下のようになってたり。

$ gdb -q a.exe
Reading symbols from a.exe...done.
(gdb) b _Dmain
Breakpoint 1 at 0x401648: file test_struct.d, line 35.
(gdb) run
Starting program: /home/TANE/develop/dlang/test/a.exe
[New Thread 10448.0x1c90]

Breakpoint 1, D main () at test_struct.d:35
35        Vec3D v ;
(gdb) n
36        v.set(0.8,0.0,0.0) ;
(gdb)
37        writef("1: %s\n",v) ;
(gdb)
38        v=v.normalize() ;
(gdb) s
test_struct.Vec3D.normalize() (this=...) at test_struct.d:15
15          Vec3D retvec ;
(gdb) p this.x
$1 = 0.80000000000000004
(gdb) s
16          double d ;
(gdb) p this.x
$2 = nan(0xc000000000000)
(gdb)

v.normalize()でメソッドに入った所ではセットした値が保持されている のですが、15行目の retvec割り当てを通ると何故か nanに化けます。 エーー?なんでだ?

Fedoraのgdcでも確認してみた所、こちらも値が化けたり。

$ cat -n test_struct.d
     1  import std.stdio;
     2  import std.math;
     3
     4  struct Vec3D
     5  {
     6    double x,y,z,w ;
     7
     8    void set(double x, double y, double z){
     9      this.x = x ;
    10      this.y = y ;
    11      this.z = z ;
    12    }
    13
    14    Vec3D normalize(){
    15      writef("xyz=(%f %f %f) %s\n", this.x, this.y, this.z, this) ;
    16      Vec3D retvec ;
    17      double d ;
    18      writef("xyz=(%f %f %f) %s\n", this.x, this.y, this.z, this) ;
    19      d=sqrt( this.x*this.x + this.y*this.y + this.z*this.z ) ;
    20      writef("d=%f\n",d) ;
    21      if( d>0.0 ){
    22        retvec.x = this.x/d ;
    23        retvec.y = this.y/d ;
    24        retvec.z = this.z/d ;
    25      }else{
    26        retvec.x = 0.1 ;
    27        retvec.y = 0.2 ;
    28        retvec.z = 0.3 ;
    29      }
    30      return(retvec) ;
    31    }
    32  }
    33
    34  void main()
    35  {
    36    Vec3D v ;
    37    v.set(0.8,0.0,0.0) ;
    38    writef("1: %s\n",v) ;
    39    v=v.normalize() ;
    40    writef("2: %s\n",v) ;
    41
    42    return ;
    43  }

$ gdc -v
Using built-in specs.
COLLECT_GCC=gdc
COLLECT_LTO_WRAPPER=/usr/local/gdc_20661_510/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-5.1.0/configure --with-pkgversion='gdc-5 ab7ac60cad' --enable-languages=c,d --prefix=/usr/local/gdc_20661_510 --disable-bootstrap --disable-nls --with-bugurl=http://bugzilla.gdcproject.org --enable-checking=yes --disable-libgomp --disable-libmudflap
Thread model: posix
gcc version 5.1.0 (gdc-5 ab7ac60cad)

$ gdc -g -O0 -frelease test_struct.d

$ ./a.out
1: Vec3D(0.8, 0, 0, nan)
xyz=(0.800000 0.000000 0.000000) Vec3D(0.8, 0, 0, nan)
xyz=(nan nan nan) Vec3D(nan, nan, nan, nan)
d=nan
2: Vec3D(0.1, 0.2, 0.3, nan)

gdbでのトレースを反映して、normalize()に入った直後に デバッグプリントを追加しました。よもやのgdc本体のバグのようです。 そういや二週間ちょっと前にメソッド呼び出し コードを改善する変更が加えられているようですが、その辺で エンバグしているのかしら?

2015/05/05

AM中に起床。

std.regex内の連想配列アクセスでsegfaultの件。 大抵はSegfaultなのですが、gdb上で動かしていると時々SIGFPE(ゼロ除算) になる場合があったり。配列のサイズが1以上のはずなのにいつの間にか0 になっている為、それを想定していないコードでゼロ除算になってしまうと いう感じ。スレッドに起因するものかも?という心当たりもあるのですがどうしたもんか。

GCをdisableにしたらエラーしなかったり。以下のようにずっこけ位置を 越えてからGCをenableするのも大丈夫そう。

  GC.disable()
  :
  ずっこけ位置
  :
  GC.enable()
  GameLoop(){
    :
  }

そもそも連想配列アクセスがスレッドセーフではない事に起因している可能性があります。 GCを動かす時は stop the world で止めているんだから、連想配列アクセス 中のスレッドがある場合はGCを先送りするとかしなくてはならないのかも。 どっちにしても、GCをいちいちコントロールしなくてはならないのは コード的にカッコ悪いです(^^;

もう一つの値が化ける件を調べたり。期待値と違って何故か値が0になっていた のですが、深くて化けてる現場にまだ辿り付けず。こちらはGCをdisableにしても 再現するので、まだ楽そうな予感。

2015/05/04

昼頃起床。

「荒木飛呂彦の漫画術」という本を読んだり。ジョジョの原作者である 荒木氏がどのように作品を生み出しているかを書いた本です。 因みに、TANEはジョジョの連載をリアルタイムにせいぜい4年くらい読んだ だけなので、波紋からスタンドに変わった最初の頃の話がうっすら記憶に あるくらいの知識です。少し読んで思ったのは、「こんなに色々考えて 描いているのか!」という所。キャラの「身上調査書」なるものの項目の 数とか、マジでか!という量です。デビューしてからしばらく売れなかった 時期の話とか、魔少年ビーティーの最終話(いわゆる10話打ち切り)で アンケート結果が伸びた話とか、とにかく読み応えがハンパない感じでした。 設定や見せ方は事前にとてもよく考えているようですが、キャラの行動については キャラ設定に基づいてこの状況だとどうするか?という感じで描いているようです。 そういえば、以前、キャラが勝手に 動く話を書いた事がありましたが、今回の本を読んで 荒木氏の場合は そうなるべく してなっているのだと判ったり。

std.regex内の連想配列アクセスでsegfaultの件。ずっこけなければ どうなるのかを最小コードで調べたり。なんとなくずっこける時は std/regex.d内?で保持している連想配列が何かしらの理由で壊れてて、 壊れている連想配列にアクセスした結果、Segfaultになっているように 思ったり。ただ、regex()をちょっと増やしたりするとズッコケ位置が 変わったりするので、壊れている瞬間を捕まえるに至らず。

2015/05/03

昼頃起床。

ネイティブのi686 MinGW-gdcのビルドを行ってみたり。 MinGW用にちょっと手を入れる必要がありましたがビルドに成功。 いくつか手持ちコードをコンパイルしてみたのですが、 Cygwinでクロスビルドしたgdcと同じで、ダメなのはネイティブgdcでも ダメでした。という訳で一応リファレンスも構築できたという感じで。
あとはx86_64がダメなのがどうにかなれば良いですが、こちらは バイナリ配布されるのを待つ方向で。勿論、バイナリを使うのではなくて、 配布用バイナリをビルドする過程で突っかかるだろうから、それにより 修正される事が期待できるという意味ですw。

std.regex内の連想配列アクセスでsegfaultする件を調べたり。 一応デバッガで追いかけても再現はするのですが、原因はよく 判らなかったり。

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 8128.0x5688]
0x004af2a4 in _aaInX (aa=..., keyti=..., pkey=0x8f3f068) at ../../../../gcc-5.1.0/libphobos/libdruntime/rt/aaA.d:269
269                 inout(Entry)* e = aa.impl.buckets[i];
(gdb) where
#0  0x004af2a4 in _aaInX (aa=..., keyti=..., pkey=0x8f3f068) at ../../../../gcc-5.1.0/libphobos/libdruntime/rt/aaA.d:269
#1  0x00504ed5 in _D3std10functional102__T7memoizeS83_D3std5regex18__T9regexImplTAyaZ9regexImplFNfAyaAxaZS3std5regex12__T5RegexTaZ5RegexVki8Z7memoizeFNfAyaAxaZS3std5regex12__T5RegexTaZ5Regex (_param_0=..., _param_1=...)
    at /usr/local/gdc031_20661_510_mingwcross/lib/gcc/i686-pc-mingw32/5.1.0/include/d/std/functional.d:677
#2  0x00547085 in _D3std5regex14__T5regexTAyaZ5regexFNeAyaAxaZS3std5regex12__T5RegexTaZ5Regex (pattern=..., flags=...)
    at /usr/local/gdc031_20661_510_mingwcross/lib/gcc/i686-pc-mingw32/5.1.0/include/d/std/regex.d:5870
#3  0x004121fa in OBJ3D.OBJ3D.this() (this=...) at OBJ3D.d:30
#4  0x00408033 in Sprite.Sprite.add3DPCG(immutable(char)[], int, double) (this=..., fname=..., pcgno=0, scale=1)
    at Sprite.d:464
#5  0x0040222a in myGameFrame.myGameFrame.GameLoop() (this=...) at myGameFrame.d:53
#6  0x004046ef in GameFrame.GameFrame.run() (this=...) at GameFrame.d:110
#7  0x004ac9bd in core.thread.Thread.run() (this=...) at ../../../../gcc-5.1.0/libphobos/libdruntime/core/thread.d:1270
#8  0x004abd05 in thread_entryPoint@4 (arg=0x2c80e80) at ../../../../gcc-5.1.0/libphobos/libdruntime/core/thread.d:236
#9  0x768f1287 in msvcrt!_itow_s () from /cygdrive/c/windows/syswow64/msvcrt.dll
#10 0x768f1328 in msvcrt!_endthreadex () from /cygdrive/c/windows/syswow64/msvcrt.dll
#11 0x74f1336a in KERNEL32!BaseThreadInitThunk () from /cygdrive/c/windows/syswow64/kernel32.dll
#12 0x775492b2 in ntdll!RtlInitializeExceptionChain () from /cygdrive/c/windows/SysWOW64/ntdll.dll
#13 0x77549285 in ntdll!RtlInitializeExceptionChain () from /cygdrive/c/windows/SysWOW64/ntdll.dll
#14 0x00000000 in ?? ()

aaA.d:269は連想配列アクセスで必ず通るようです。 ウインドウハンドラのリストにも使用しているものですから、ブレークポイント を張ると止まりまくってしまうのが、面倒臭い感じになってます。 また、同じコードを他のアプリでも使っているのですが、そちらでは 問題無く動く(というか動かないのが、とあるアプリ一つだけ)為、 最小の再現コードが書ける気がしないです。

うーん、どうもTupleが怪しい気がするのですがなんとも。

2015/05/02

AM中に起床。ちょろり休出。

本屋で散財。

先日の32bit MinGW-gdcの対応方法について。バックエンドに手を入れて しまうとgdc以外の言語をビルドするとハマる可能性があります。 バックエンドは元のままgdcの生成するGIMPLEで関数呼び出しコードを コントロールする方法があれば良いのですが、可能か否かはよくわからず。

先日のgdcを使ってもいくつか不具合があるもよう。


安定までの道のりは長いです。

32bit-MinGW環境の標準gccが壊れていたのをダウングレードで直したり。 壊れているのを置かないで欲しいなぁ。てかMSYSよく判らん。

ネイティブの i686 MinGWで gcc-5.1.0 をビルドしてみたり。 libssp/ssp.cへのパッチはMinGWでも必要っぽい。ひとまずはビルドできたり。

cairoのリンクに失敗するようになっていたので、ビルドしたMinGW gcc-5.1.0で 再ビルドを試みているのですが、何故かtextセクションが空のライブラリができてしまったり。 どうやらコンパイラオプションに -fltoを付けると謎のオブジェクトファイルが 生成されてしまうようで、オプションを外せばイケました。

2015/05/01

本日はお休み。

先日のコードをFedoraの方で試してみたところ、再現コードになっていたかも。全コードは以下の通り。

$ cat -n mingwgdcfailed_test3.d
     1  import std.stdio;
     2  import std.string;
     3
     4  size_t testFunc(in void* p){
     5    writef("Here is testFunc %08x %08x\n",&p,p) ;
     6    return(0) ;
     7  }
     8
     9  class Foo{
    10    this(){
    11    }
    12    size_t FootestFunc(){
    13      writef("Here is FootestFunc %08x\n",&this) ;
    14      return(0) ;
    15    }
    16  }
    17
    18  void main()
    19  {
    20    Foo f = new Foo() ;
    21
    22    size_t function(in void*) tF=&testFunc;
    23    size_t delegate() dg_footestfunc = &f.FootestFunc ;
    24
    25    tF(cast(void*)f) ;
    26    testFunc(cast(void*)f) ;
    27    f.FootestFunc() ;
    28    dg_footestfunc() ;
    29  }

$ i686-pc-mingw32-gdc.exe -g -fdump-tree-all -O0 -frelease mingwgdcfailed_test3.d

$ ./a.exe
Here is testFunc 0028fc40 00ff1fe0
Here is testFunc 0028fc40 00ff1fe0
Here is FootestFunc 0028fc2c
Here is FootestFunc 0028fc2c

これをFedoraのgdc(mutilibビルド)で試してみた結果が以下。

$ gdc -m32 -g -fdump-tree-all -O0 -frelease mingwgdcfailed_test3.d

$ ./a.out
Here is testFunc ffa9f260 f75edff0
Here is testFunc ffa9f260 f75edff0
Here is FootestFunc ffa9f260
Here is FootestFunc ffa9f260

MinGW-gdcの方は関数呼び出しとメソッド呼び出しで、&p と&thisの値が 違っていますが linux-gdcの方は同じです。つまり、MinGW-gdcで引数が 化けるんですけど?の状況が再現できているようです。 また、GIMPLE的にはMinGWとLinuxとで(ラベル番号のズレはありますが)同じ結果に なりました。なので、バックエンドの問題なのか?という予感。

このコードを大丈夫な DMD2.062ベースのMinGW-gdcでコンパイル&実行してみた所、 以下のようになりました。

$ gdc.exe -v
Using built-in specs.
COLLECT_GCC=C:\MinGW\gdc031_2062_480\bin\gdc.exe
COLLECT_LTO_WRAPPER=c:/mingw/gdc031_2062_480/bin/../libexec/gcc/mingw32/4.8.0/lto-wrapper.exe
Target: mingw32
Configured with: ../gcc-4.8.0/configure --build=mingw32 --with-arch=i686 --enable-languages=c,c++,d,lto --prefix=/mingw/gdc031_2062_480 --enable-threads --disable-nls --enable-sjlj-exceptions --disable-bootstrap
Thread model: win32
gcc version 4.8.0 (GCC)

$ gdc.exe -g -fdump-tree-all -O0 -frelease mingwgdcfailed_test3.d

$ ./a.exe
Here is testFunc 0028fc00 00721ff0
Here is testFunc 0028fc00 00721ff0
Here is FootestFunc 0028fc00
Here is FootestFunc 0028fc00

また、DMD2.066.1でも確認。

$ ~/develop/dlang/dmd/dmd_2.066.1/windows/bin/dmd.exe -v | head
DMD32 D Compiler v2.066.1
Copyright (c) 1999-2014 by Digital Mars written by Walter Bright
Documentation: http://dlang.org/
Usage:
  dmd files.d ... { -switch }

  files.d        D source files
  @cmdfile       read arguments from cmdfile
  -allinst       generate code for all template instantiations
  -c             do not link

$ ~/develop/dlang/dmd/dmd_2.066.1/windows/bin/dmd.exe mingwgdcfailed_test3.d

$ ./mingwgdcfailed_test3.exe
Here is testFunc 0018fd54 00441fe0
Here is testFunc 0018fd54 00441fe0
Here is FootestFunc 0018fd54
Here is FootestFunc 0018fd54

いずれも、linux-gdcと同じ結果となりました。

gccのソースを眺めていたところ、gcc/config/i386/i386.c に 以下のようなコメントを見つけたり。

   7694           /* Fastcall allocates the first two DWORD (SImode) or
   7695             smaller arguments to ECX and EDX if it isn't an
   7696             aggregate type .  */

なんとなくこれっぽいぞ?
fastcallとは関数の引数が少ない場合にスタック渡しではなくレジスタ渡しに するという仕組みです。どうやらfastcallのコードが生成されているものと 推測してみたり。ただ、gdc側では特にfastcallで関数呼び出しを行う制御を している訳ではなさそうなので、treeからRTLに変換する時にgcc側で勝手に コードを生成している気がしたり。fastcallを抑止するコンパイラオプション があるかな?と思ったのですがそれは無い模様。
しかし、納得いかない点があります。 以前ベースgccは4.8.xで同じで、 gdcだけ2.062と2.065で比べたとき、2.065の方だけズッコケました。 この為、gccは関係無くてgdcのバージョンに依存するものだと考えていました。 ですが、gccのRTL生成の問題だとすると、ベースgccのバージョンに連動 しないというのは辻褄が合いません。

そんな訳で、gcc/config/i386/i386.cを以下のようにいじってみたり。

$ diff -b -c gcc/config/i386/i386.c.orig2 gcc/config/i386/i386.c
*** gcc/config/i386/i386.c.orig2        2015-04-26 01:58:03.884339400 +0900
--- gcc/config/i386/i386.c      2015-05-01 21:25:50.064073200 +0900
***************
*** 5742,5750 ****
        else if (lookup_attribute ("stdcall", attrs))
        ret |= IX86_CALLCVT_STDCALL;
        else if (lookup_attribute ("fastcall", attrs))
!       ret |= IX86_CALLCVT_FASTCALL;
        else if (lookup_attribute ("thiscall", attrs))
!       ret |= IX86_CALLCVT_THISCALL;

        /* Regparam isn't allowed for thiscall and fastcall.  */
        if ((ret & (IX86_CALLCVT_THISCALL | IX86_CALLCVT_FASTCALL)) == 0)
--- 5742,5750 ----
        else if (lookup_attribute ("stdcall", attrs))
        ret |= IX86_CALLCVT_STDCALL;
        else if (lookup_attribute ("fastcall", attrs))
!       ret |= IX86_CALLCVT_CDECL ; //IX86_CALLCVT_FASTCALL;
        else if (lookup_attribute ("thiscall", attrs))
!       ret |= IX86_CALLCVT_CDECL ; //IX86_CALLCVT_THISCALL;

        /* Regparam isn't allowed for thiscall and fastcall.  */
        if ((ret & (IX86_CALLCVT_THISCALL | IX86_CALLCVT_FASTCALL)) == 0)
***************
*** 5769,5775 ****
        || ix86_function_type_abi (type) != MS_ABI)
      return IX86_CALLCVT_CDECL | ret;

!   return IX86_CALLCVT_THISCALL;
  }

  /* Return 0 if the attributes for two types are incompatible, 1 if they
--- 5769,5775 ----
        || ix86_function_type_abi (type) != MS_ABI)
      return IX86_CALLCVT_CDECL | ret;

!   return IX86_CALLCVT_CDECL ; //IX86_CALLCVT_THISCALL;
  }

  /* Return 0 if the attributes for two types are incompatible, 1 if they

その結果が以下。

$ i686-pc-mingw32-gdc.exe -g -O0 -frelease mingwgdcfailed_test3.d

$ ./a.exe
Here is testFunc 0028fc60 00ad1fe0
Here is testFunc 0028fc60 00ad1fe0
Here is FootestFunc 0028fc60
Here is FootestFunc 0028fc60

$ i686-pc-mingw32-gdc.exe -v
Using built-in specs.
COLLECT_GCC=i686-pc-mingw32-gdc
COLLECT_LTO_WRAPPER=/usr/local/gdc031_20661_510_mingwcross/libexec/gcc/i686-pc-mingw32/5.1.0/lto-wrapper.exe
Target: i686-pc-mingw32
Configured with: ../gcc-5.1.0/configure --with-pkgversion='gdc-5 ab7ac60cad' --build=i686-pc-cygwin --host=i686-pc-cygwin --target=i686-pc-mingw32 --enable-languages=d --prefix=/usr/local/gdc031_20661_510_mingwcross --with-sysroot=/usr/i686-pc-mingw32/sys-root --enable-threads --disable-nls --enable-sjlj-exceptions --disable-bootstrap
Thread model: win32
gcc version 5.1.0 (gdc-5 ab7ac60cad)

ひゃっっほーーーっっっっ!!! 久々にfontサイズを 変えてみたくなりましたよ(^-^; std.regexが使えるようになったので、手持ちのWindowsアプリコードも 動くようになりました。やったね(^^)v

gdc2.066-32bit-mingw-gdcでWindowsアプリ

因みに、64bitターゲットでは全て IX86_CALLCVT_CDECL で関数呼び出し されます。この為、64bitターゲットでは、32bitのそれのような事は 起こりません。ただ、Linuxでmultilibコンパイルして-m32がうまく 動く理由は定かではありません。

gdcの2.065が MinGWに対応したのが1年前 で、結局動かすのに 1年かかってしまいました(^^;; まぁ、Cygwinでクロスビルドする技とか も得られたのでよしとしよう。


TOP PREV