ToDo:
昨日ふと困ったバグは少しおもしろかった。バグ自体はなんてことないものなんだけど。 SDL 使って書いてるもので、青だけ出ない。なんか青くあるべき場所が黒い。
なんか SDL のビデオドライバとかがおかしなことになって、ピクセルフォーマット勘違いしてたりするのかなーとか最初は思ったんだけど、まぁよく考えると Mac なんていうメジャーなプラットフォームにそんなバグあるわけない。そもそも白が出てる部分もあるんで、青が完全に死んでるわけじゃない。けど、灰色が出るべきところは黄色ぽくなってたりして、やっぱ青がおかしい感じではあるんだよなあ、と。
で、色つくってる部分のコードを見てみてると、
Uint32 c = 0; switch (color) { case EMPTY: c = SDL_MapRGB(scr_->format, 0, 0, 0); break; case OJAMA: c = SDL_MapRGB(scr_->format, 127, 127, 127); break; case WALL: c = SDL_MapRGB(scr_->format, 255, 255, 255); break; case RED: c = SDL_MapRGB(scr_->format, 255, 0, 0); break; case BLUE: c = SDL_MapRGB(scr_->format, 0, 0, 255); break; case YELLOW: c = SDL_MapRGB(scr_->format, 255, 255, 0); break; case GREEN: c = SDL_MapRGB(scr_->format, 0, 255, 0); break; default: break; } //return c;
と、最後の return が無かった。ああまたやらかしたかー、アホだなー、そりゃヘンなことも起こるよなーと思って、その場は次にいった。
その後の呑み会で、いやそんなわけないだろうと思う。そりゃヘンなことも起こるかもしれないけど、上記のコードで青だけ落ちるってのはどう考えてもおかしい。というのは SDL_MapRGB が返り値として RAX を代入してくれてるはずなんで、この return は別に無くても大丈夫な気がする。
switch とかってなにやら賢いことするからそれで BLUE のパスだけ RAX 壊れたりするのかなーと思って、この部分の逆アセンブリ見てみても特に RAX が壊れる感じがしない、というか SDL_MapRGB を呼んだ直後に ret している。まあ switch のコードはなかなか賢そうな感じで、やるなあとか思ったけど…
でまーとなるとなんでかなーと思って考えてみると、むしろこの関数を呼ぶ側があやしいんじゃないかと。特にインライン展開されてたらそっちを見ないといけない。見てみると、インライン展開はされてないんだけど、
Uint32 c = GetPuyoColor(color); SDL_FillRect(scr_, &r, c);
が
0000000100008736 callq 0x100014d72 ; symbol stub for: __ZN6GuiSdl12GetPuyoColorEc 000000010000873b movq 0x08(%rbx),%rdi 000000010000873f leaq 0xffffff58(%rbp),%rsi 0000000100008746 callq 0x100014e0e ; symbol stub for: _SDL_FillRect
となっていた。つまり RAX を引数として使ってない。 return を入れてやると
0000000100008841 callq 0x100014d72 ; symbol stub for: __ZN6GuiSdl12GetPuyoColorEc 0000000100008846 movq 0x08(%r15),%rdi 000000010000884a movq %r14,%rsi 000000010000884d movl %eax,%edx 000000010000884f callq 0x100014e0e ; symbol stub for: _SDL_FillRect
となる。なるほど return が無いバージョンは不定な値返してる、ってのは同じ compile unit にあるからわかるわけで、だからどうせ意味ないなら次に渡す必要もないよねー的な感じで消されちゃってるんだろう。関数またいだフロー解析的な最適化みたいな感じなのかな?
でまあ RDX (SDL_FillRect の第三引数) は SDL_MapRGB 内でたまたま青を合成する前の値を保持するレジスタとして使われて、その後いじられなかったんだろう、と思う。
なにやらコンパイラさん賢いなあというか、ややびっくり感が強い
(03:22)
JS でよく a=1.5 とかを 1 に切り捨てをするために、 a|0 とか書く。浮動小数を整数にする時のゴルフイディオム的な感じ。
さて、デカい浮動小数に対してこれをやると int の範囲に落ちる。
js> 1e20|0 1661992960
て感じ。 irb で確認してやると
irb(main):006:0> (10**20)%(2**32) => 1661992960
ただしい。 1e21 になると signed int の値域で考えると負数になるので少し ruby 側の処理が変わるけど
js> 1e21|0 -559939584 irb(main):007:0> (10**21)%(2**32)-2**32 => -559939584
となって一致する。 1e22 も一致するんだけど、 23 から話がおかしくなる。
js> 1e22|0 -1304428544 irb(main):010:0> (10**22)%(2**32)-2**32 => -1304428544
js> 1e23|0 -167772160 irb(main):011:0> (10**23)%(2**32)-2**32 => -159383552
js> 1e24|0 -1610612736 irb(main):012:0> (10**24)%(2**32)-2**32 => -1593835520
js> 1e25|0 -2147483648 irb(main):013:0> (10**25)%(2**32)-2**32 => -3053453312
js> 1e26|0 0 irb(main):014:0> (10**26)%(2**32)-2**32 => -469762048
さてこれは何故でしょうか、ってのを考えると、精度の問題。 double の 53bit の精度から下は切り上げ切り下げの後に 0 になっちゃうわけだけど、 1e22 まではその切れる部分はもともと全部 0 だったから問題なかったけど、 1e23 から 1 が入ってる場合があって、そこが消えちゃうとまずい、と。
こういうのもちょっと面白い
js> 18014398509481986|0 0 js> 18014398509481987|0 4
まあなんか、 ruby でも
irb(main):025:0> 1e23.to_i => 99999999999999991611392 irb(main):024:0> 1e23.to_i%2**32-2**32 => -167772160
とかやれば再現できるわけで、よく考えれば不思議でも不気味でもなんでもないんだけど、なんか JS キモいな、と思ってしまったのは、唯一の組み込みの数値型が浮動小数だからかな…
(03:24)
CD-R が見つからないので PXE boot でのインストールにチャレンジ
/etc/dhcp/dhcpd.conf
default-lease-time 86400; max-lease-time 259200; ddns-update-style none; subnet 192.168.11.0 netmask 255.255.255.0 { range 192.168.11.200 192.168.11.250; option subnet-mask 255.255.255.0; option broadcast-address 192.168.11.255; option routers 192.168.11.1; option domain-name-servers 192.168.11.1; option domain-name "shinh.org"; deny unknown-clients; } host pxeclient { hardware ethernet 00:1D:72:8A:AD:D8; fixed-address 192.168.11.200; filename "/pxelinux.0"; next-server 192.168.11.17; }
/etc/xinetd.d/tftp の disable を no に。
$ sudo systemctl restart dhcpd.service $ sudo systemctl restart xinetd.service
/var/lib/tftpboot を適当に準備
find /var/lib/tftpboot /var/lib/tftpboot/ /var/lib/tftpboot/initrd.img /var/lib/tftpboot/pxelinux.cfg /var/lib/tftpboot/pxelinux.cfg/default /var/lib/tftpboot/vmlinuz /var/lib/tftpboot/pxelinux.0
pxelinux.0 は
$ sudo cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot
で良し。 vmlinuz と initrd.img はちゃんとバージョンをあわせる。
# wget http://ftp.riken.jp/Linux/fedora/releases/17/Fedora/x86_64/os/images/pxeboot/vmlinuz # wget http://ftp.riken.jp/Linux/fedora/releases/17/Fedora/x86_64/os/images/pxeboot/initrd.img
あと pxelinux の設定ファイルは
# cat pxelinux.cfg/default prompt label fedora kernel vmlinuz append load initrd=initrd.img devfs=nomount method=http://ftp.riken.jp/Linux/fedora/releases/17/Fedora/x86_64/os/
などとした。 ISO を http で供給する方法だとローカルのディスクサイズが足りなくて、 NFS でなんかする方法はうまくいかなくてあきらめたんだけど、今にして思うとたぶん squashfs.img をマウントしたものを見せるべきだったんだろうな…
(03:17)
前 | 2012年 12月 |
次 | ||||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
全てリンクフリーです。 コード片は自由に使用していただいて構いません。 その他のものはGPL扱いであればあらゆる使用に関して文句は言いません。 なにかあれば下記メールアドレスへ。