Debian GNU/Linux (lenny) で、0.0.0.0 を getnameinfo で逆引きすると、5秒かかることに気がつく。
% cat tst.c #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> int main(int argc, char *argv[]) { struct sockaddr_in sa; char host[4096], serv[4096]; int ret; sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_port = 0; ret = getnameinfo((const struct sockaddr *)&sa, sizeof(sa), host, sizeof(host), serv, sizeof(serv), 0); if (ret != 0) { fprintf(stderr, "getnameinfo: %s\n", gai_strerror(ret)); exit(1); } printf("host: %s\n", host); printf("serv: %s\n", serv); return 0; } % gcc tst.c % time ./a.out host: 0.0.0.0 serv: 0 ./a.out 0.00s user 0.00s system 0% cpu 5.029 total
調べてみると /etc/nsswitch.conf の hosts に mdns4 が入っているのが原因のようだ。
OpenSolaris (の zfs) では、同じ順番で複数のファイルを作っても、readdir で読み出される順序は変わるようだ。
% ruby -ve ' 10.times {|d| d = d.to_s Dir.mkdir(d) 10.times {|i| open("#{d}/#{i}", "w") {} } p Dir.entries(d) }' ruby 1.8.7 (2008-08-11 patchlevel 72) [i386-solaris2.11] [".", "..", "2", "8", "5", "1", "6", "4", "9", "3", "7", "0"] [".", "..", "1", "6", "2", "8", "5", "7", "0", "4", "9", "3"] [".", "..", "1", "6", "8", "2", "5", "7", "0", "4", "3", "9"] [".", "..", "0", "7", "9", "3", "4", "6", "1", "5", "2", "8"] [".", "..", "2", "8", "5", "1", "6", "4", "9", "3", "7", "0"] [".", "..", "8", "2", "5", "1", "6", "4", "3", "9", "7", "0"] [".", "..", "0", "7", "9", "3", "4", "6", "1", "5", "2", "8"] [".", "..", "3", "9", "4", "0", "7", "5", "8", "2", "6", "1"] [".", "..", "5", "2", "8", "6", "1", "9", "3", "4", "0", "7"] [".", "..", "4", "9", "3", "7", "0", "2", "8", "5", "1", "6"]
ARM の浮動小数点が mixed endian というのは過去の話だったらしい。
EABI では普通のようだ。
Linux では . と .. が readdir で初めに出てこないことがあるという話に出会った。本当に?
% ruby -ve 'p Dir.entries("/home")' ruby 1.8.7 (2008-08-11 patchlevel 72) [arm-linux-eabi] [".", "akr", ".."]
本当のようだ。
readdir で最初のふたつを読み飛ばすというのはダメで、ちゃんと . と .. という名前で検査しなければいけないということだな。
chkbuild の diff で unified diff をやめた。
diff は順序に敏感なので、zfs とかで build log 内の順番が不安定だと変化として検出されるのが多すぎる。
以前から、minitest のテスト順とか、不安定なところはいくつかあって個々に対処していたのだが、もう順序はまったく気にしないことにする。(また、同じ行が何行あるかも気にしないことにする)
で、順序に依存しない形式に変えた。
これにより、変更点を抽出するという問題はより簡単になる。
ファイル A, B があったとして、B の各行について、A に同じ行が含まれるかどうか印をつけたい。(また同様に、A の各行について、B に同じ行が含まれるかどうか印をつけたい)
さて、どうするか。
気楽にやるなら、A の各行をハッシュテーブルに登録し、B の各行についてハッシュテーブルを参照すればいい。
しかし、それだと A 全体をメモリに読み込むことになる。A が大きくなりうる状況だと、避けたいところである。
それを避けるにはハッシュテーブルに dbm の類を使う、というのが考えられる。が、Ruby のは、あったりなかったりしたり、制約が強かったり、ちょっと微妙なので使いたくない。それに、激しくランダムアクセスしそうで、なんとなく遅そうな気がする。(測ってないので気のせいかもしれない)
では、ということで、ソートでやってみた。A, B をそれぞれソートして、そのときに元の行番号もつけておく。両方ソート済みであれば、同じ行が含まれるかどうかはシーケンシャルに読むだけで分かるので印をつけられる。そんで、印をつけた後に行番号でソートしなおすと元の順番に戻る。行番号を除去すればできあがり。
ここで、ソートには sort コマンドを使うので、ソートに ruby のメモリ空間は消費しない。そして、sort コマンドはきっとマージソートなので、そっちもそれほど消費しないはずである。たぶん。
図示すると、こんなかんじでデータが流れる。
changes.dot:
digraph g { a1 [label = "A"] b1 [label = "B"] a2 [label = "lnum,line in A\nsorted by lnum"] b2 [label = "lnum,line in B\nsorted by lnum"] a3 [label = "lnum,line in A\nsorted by line"] b3 [label = "lnum,line in B\nsorted by line"] cmp [label = "compare line and add mark", shape=record] a4 [label = "lnum,mark,line in A\nsorted by line"] b4 [label = "lnum,mark,line in B\nsorted by line"] a5 [label = "lnum,mark,line in A\nsorted by lnum"] b5 [label = "lnum,mark,line in B\nsorted by lnum"] a6 [label = "A with mark"] b6 [label = "B with mark"] a1->a2 [label="add lnum"] a2->a3 [label="sort"] a3->cmp->a4 a4->a5 [label="sort"] a5->a6 [label="delete lnum"] b1->b2 [label="add lnum"] b2->b3 [label="sort"] b3->cmp->b4 b4->b5 [label="sort"] b5->b6 [label="delete lnum"] }
で、それを実現するコードの抜粋が、こうである。
a2 = encode_lines(path_a) a3 = sort_by_content(a2.path) a2.close(true) b2 = encode_lines(path_b) b3 = sort_by_content(b2.path) b2.close(true) a4, b4 = add_mark(a3, b3) a3.close(true) b3.close(true) a5 = sort_by_linenum(a4.path) a4.close(true) b5 = sort_by_linenum(b4.path) b4.close(true)
思うに、このコードの残念なところは、図に示した構造をプログラムの構文木やインデントという視覚的構造で表現できていないことである。close(true) が邪魔なのもあるが、それがなくてもフラットな構造でよろしくない。
表現したいものが木なのだから、プログラムの木構造でそれを表現できてもいけなくはないはずである。というかそうできるようにどうにかするというのが工夫ではないか。
さて、どうデザインすれば、プログラムの木構造とデータの流れを合わせることができ、また、テンポラリファイルを自動的に (不要になった時点で即座に) 削除できるか。あぁ、データが小さかったらテンポラリファイルからメモリ内で済ます方が良くて、それも自動的にやってほしいという要求もある。
FSIJ 月例会で gcc の話を聞く。
gcc の話を聞いて思い立ち、(まだリリースされていない) gcc-4.5 をビルドして、ruby をためしてみる。
テストすると unpack がうまく動かないことがあるようだ。
縮めてみるとこんなかんじになった。
% cat t.c #include <stdio.h> #include <string.h> char ary[] = "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f"; int main(int argc, char *argv[]) { int flag = *argv[1]; union { long v; char a[8]; } tmp; tmp.v = 0; int len = flag ? 8 : 4; memcpy((char*)tmp.a, ary, len); if (!flag) { printf("!flag\n"); } if (tmp.v < 10) printf("bad\n"); else printf("good\n"); return 0; } % gcc -v -O2 t.c Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/home/gcc/libexec/gcc/x86_64-unknown-linux-gnu/4.5.0/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: ../gcc/configure --prefix=/home/gcc --enable-languages=c --disable-multilib Thread model: posix gcc version 4.5.0 20100217 (experimental) (GCC) COLLECT_GCC_OPTIONS='-v' '-O2' '-mtune=generic' /home/gcc/libexec/gcc/x86_64-unknown-linux-gnu/4.5.0/cc1 -quiet -v t.c -quiet -dumpbase t.c -mtune=generic -auxbase t -O2 -version -o /tmp/ccBV1zVb.s GNU C (GCC) version 4.5.0 20100217 (experimental) (x86_64-unknown-linux-gnu) compiled by GNU C version 4.5.0 20100217 (experimental), GMP version 4.2.2, MPFR version 2.3.1, MPC version 0.8.1 GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 ignoring nonexistent directory "/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../x86_64-unknown-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/local/include /home/gcc/include /home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/include /home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/include-fixed /usr/include End of search list. GNU C (GCC) version 4.5.0 20100217 (experimental) (x86_64-unknown-linux-gnu) compiled by GNU C version 4.5.0 20100217 (experimental), GMP version 4.2.2, MPFR version 2.3.1, MPC version 0.8.1 GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 Compiler executable checksum: 335cca3864cc5c513a149712a32ade04 COLLECT_GCC_OPTIONS='-v' '-O2' '-mtune=generic' as -V -Qy -o /tmp/ccwo28ui.o /tmp/ccBV1zVb.s GNU assembler version 2.18.0 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.18.0.20080103 COMPILER_PATH=/home/gcc/libexec/gcc/x86_64-unknown-linux-gnu/4.5.0/:/home/gcc/libexec/gcc/x86_64-unknown-linux-gnu/4.5.0/:/home/gcc/libexec/gcc/x86_64-unknown-linux-gnu/:/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/:/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/ LIBRARY_PATH=/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/:/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-O2' '-mtune=generic' /home/gcc/libexec/gcc/x86_64-unknown-linux-gnu/4.5.0/collect2 --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/../lib64/crt1.o /usr/lib/../lib64/crti.o /home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/crtbegin.o -L/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0 -L/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/../../.. /tmp/ccwo28ui.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /home/gcc/lib/gcc/x86_64-unknown-linux-gnu/4.5.0/crtend.o /usr/lib/../lib64/crtn.o % ./a.out a bad
strict-aliasing だとは思うのだが、-fno-strict-aliasing でも変わらない。
なお、もともとのコードは union は使っていなかったが、上記のように union を使うようにしても挙動は変わらない。
まぁ、もっと安全に書くべきだろうな。
以前からイーサネットハブとして、FX-08Mini を使っている。小さいくせに 8ポートで気に入っているが、ギガビットでないのが玉に瑕である。同じサイズでギガビットなのがでないものかな。
それはそれとしてふと検索してみると、オーディオ関係で FX-08Mini の話が見つかる。これは音質が良くなるハブなのだそうな。ふーん。
玄柴で Debian の kernel package を作り直してみた。
Debian Linux Kernel Handbook - Common kernel-related tasks に書いてあるとおりやってできたはできた。
ただ、fakeroot debian/rules binary に 31時間ほどかかった。
おそらく、cross compile でやる方向が賢いのだろう。
もう一回、今度は
% fakeroot debian/rules debian/stamps/source-base % fakeroot debian/rules debian/stamps 玄柴のために eSATA 有効に変更 % fakeroot make -f debian/rules.gen binary-arch_armel_none_kirkwood
として必要なものだけ作ったら 5時間で済んだ。
31時間もかかるのは初めにドキュメントを生成しているのが長い感じ? xsltproc がずーっと動いていたからなぁ。
最初、書いてあるように fakeroot debian/rules debian/build debian/stamps としたら debian/build というターゲットが無くて... って今見たらそんな記述は無い。fakeroot debian/rules source というところがそうなっていたような気がするのだが。
東京Ruby会議03
折り紙をやってみた
発表した
[latest]