親子丼、おかわり
所用で田舎へ行ってきた。実りの秋でお土産いっぱい。
色々な種類の葡萄、りんご、プラム、栗、ブルーベリー。胡桃も有ったけどまだ今年のもの ではないので、次回の楽しみにした。
後、蜂蜜も、りんごの花のやつや桃のやつ、レンゲの花のやつとか、いろいろあったけど 食べきれそうになかったので、遠慮してしまった。
蜂蜜もいろいろな種類のやつを並べて見ると、色あいが薄いの濃いのとあって、見てるだけ で楽しめる。これも蜂さんの努力の賜物。
そう言えば、実家の軒先に、蜂が巣を作ってしまい大変だったとか。やっとの思いで 巣を撤去し、以後、蜂が嫌いな薬を散布したとか。
おいらが子供の頃は、学校サボって裏山へ地蜂を取りに行き、蜂の子をかすめてきたなあ。 蜂の子は、理科の実験室にあった、アルコールランプで炙って醤油垂らして食べたっけ。 古き良き思い出。
EHアンテナとか、スーパーラドアンテナ
今月号のCQ誌の表紙は、EHアンテナが誇らしげに飾っていた。135KHz帯がアマチュアに 公開されたのはいいんだけど、アンテナどうすべ?
ハーフラムダの大ポールで、アンテナ長さが1100mにもなると、そんなの張れる敷地無い よね。そこで、登場したのがEHアンテナ 極めて小さいアンテナなので、アパマン無線家の注目を浴びている。
また、小ささから言うとスーパーラドアンテナ も、負けてはいない。このアンテナは日本人の方が開発者 であり、第二の「八木宇田アンテナ」として、世界制覇なるかな? 注目しましょう。
親子丼、おかわり
前回は、chicken + egg の、一番美味しい所まで食べつくしていなかった。今回は、FreeBSDに 舞台を移して、じっくりと味わってみる事にする。
まずは、インタープリタ対コンパイラの対決だな。csi と言うのが、インタープリタ。cscは コンパイラ(ドライバー)だ。コンパイラの本体は、chicken。こちらは、素で使う事は無いだろう。
ソースを展開した中に、ベンチマーク用のコードが有ったので、試してみる。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ cat fib.scm ;;; fib.scm (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))) ) ) (time (pp (fib 35)))
オリジナルでは、(fib 30)を計算してるんだけど、ちょっと多めに変更した。 まずは、インタプリタでやってみる。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ csi CHICKEN (c)2008-2009 The Chicken Team (c)2000-2007 Felix L. Winkelmann Version 4.1.0 - SVN rev. 15292 freebsd-unix-gnu-x86 [ manyargs dload ptables applyhook ] compiled 2009-09-17 on fb.kuma.net (FreeBSD) #;1> (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))) ) ) #;2> (time (pp (fib 35))) 9227465 93.04 seconds elapsed 1.947 seconds in (major) GC 10 mutations 170 minor GCs 631 major GCs
これだけじゃ、速いのか遅いのか、比べる対象が無いので、我らがgoshに登場して貰おう。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ gosh-rl gosh> (define (fib n) ..... (if (< n 2) ..... n ..... (+ (fib (- n 1)) (fib (- n 2))) ) ) fib gosh> (time (fib 35)) ;(time (fib 35)) ; real 17.613 ; user 17.242 ; sys 0.023 9227465
この速さは、VM用にコンパイルしている裏方さんのおかげでしょう。 それでは、chickenの売り、コンパイラ君の登場です。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ csc fib.scm [sakae@fb ~/chicken-4.1.0/benchmarks]$ ./fib 9227465 11.918 seconds elapsed 0.074 seconds in (major) GC 0 mutations 941 minor GCs 29 major GCs
大分早くなりましたねえ。更に爆速モードも用意されてます。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ csc -Ob fib.scm [sakae@fb ~/chicken-4.1.0/benchmarks]$ ./fib 9227465 0.697 seconds elapsed 0 seconds in (major) GC 0 mutations 0 minor GCs 0 major GCs
参考までに、Cでもfibをやってみた。
[sakae@fb ~/tmp]$ cat fibc.c #include <stdio.h> long fib(long n){ if ( n < 2){ return n; } else { return fib(n - 1) + fib(n - 2); } } main(){ printf("%ld\n", fib(35L)); } [sakae@fb ~/tmp]$ gcc -O3 -fomit-frame-pointer fibc.c [sakae@fb ~/tmp]$ time ./a.out 9227465 real 0m0.695s user 0m0.679s sys 0m0.000s
素晴らしすぎますよ。出来たバイナリーも程々にコンパクトです。ここから言える事は、インタプリタ を使って十分に虫取りをしておいて(その為に、step実行や、trace機能が搭載されてる)、 実際に使う時は、コンパイルしたのをどうぞって方針のようだ。
goshは使い捨て(でなくてもいいけど)のスクリプトをさっと実行すると言うフットワークの 軽さを求めてるのに対し、chickenは長く使うアプリ用って事かな。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ ls -l fib -rwxr-xr-x 1 sakae kuma 9636 Sep 30 02:33 fib* [sakae@fb ~/chicken-4.1.0/benchmarks]$ strip fib [sakae@fb ~/chicken-4.1.0/benchmarks]$ ls -l fib -rwxr-xr-x 1 sakae kuma 6540 Sep 30 02:35 fib*
但し、このバイナリーは、chickenのライブラリーに依存してますので、何処に 持って行っても動く訳ではありません。chickenのシステムが有る事を前提としてます。
[sakae@fb ~/chicken-4.1.0/benchmarks]$ ldd fib fib: libuchicken.so => /usr/local/lib/libuchicken.so (0x33c84000) libm.so.4 => /lib/libm.so.4 (0x33fa7000) libc.so.6 => /lib/libc.so.6 (0x33fbd000)
chickenの独立
コンパイラーの章の「生成された C ファイルを配布する」に、chickenシステムから分家する 方法が書いてある。例に倣ってやってみた。
[sakae@fb ~/work]$ chicken hello.scm -optimize-level 3 -output-file hello.c [sakae@fb ~/work]$ gcc -static -Os -fomit-frame-pointer runtime.c library.c eval.c \ > extras.c hello.c -o hello -lm /var/tmp//ccvaxwPt.o(.text+0x2ccb): In function `C_eval_toplevel': : undefined reference to `C_expand_toplevel' /var/tmp//cc9CCYm4.o(.text+0xf3d): In function `C_extras_toplevel': : undefined reference to `C_data_structures_toplevel' /var/tmp//cc9CCYm4.o(.text+0x1aac): In function `f_1288': : undefined reference to `C_ports_toplevel' /var/tmp//cc7SQ0eC.o(.text+0x250): In function `f_16': : undefined reference to `C_data_structures_toplevel' /var/tmp//cc7SQ0eC.o(.text+0x2bc): In function `f_19': : undefined reference to `C_ports_toplevel' /var/tmp//cc7SQ0eC.o(.text+0x394): In function `f_25': : undefined reference to `C_srfi_69_toplevel'
何よこれ。見事にエラーじゃん。でも、的確なエラーが出てくるだけまし。エラーをヒントに ひたすら定義箇所を grepを使って探す。
結局、expand.c data-structures.c ports.c srfi-69.c を追加した所で、無事にコンパイルを 完了した。
[sakae@fb ~/work]$ ldd hello ldd: hello: not a dynamic ELF executable [sakae@fb ~/work]$ file hello hello: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), for FreeBSD 6.4 (604100), statically linked, FreeBSD-style, stripped [sakae@fb ~/work]$ ls -l hello -rwxr-xr-x 1 sakae kuma 894084 Sep 30 03:05 hello*
コンパイラーフラグからも想像出来るけど、静的リンクで実行環境を一切喝采抱え込んだ、巨大な バイナリーが出来た。巨大になる事を開発者は気にしてて、サイズを小さくしてねと、gccに お願いしてる所が微笑ましい。おいらは、そこまでするなら、stripして更に贅肉を落とす 小細工をしちゃったよ。
で、先ほど grep してて気が付いたんだけど
[sakae@fb ~/chicken-4.1.0]$ ls -l *eval* -rw-r--r-- 1 sakae kuma 752253 Jul 31 22:33 eval.c -rw-r--r-- 1 sakae kuma 62630 Jul 31 22:31 eval.scm -rw-r--r-- 1 sakae kuma 687305 Jul 31 22:35 ueval.c
cscコマンドは、*.scm をコンパイルして *.c を出力してくれるのはいいんだけど、上の場合の ueval.c は、何物よ? ちょいとソースを開いてみたら
[sakae@fb ~/chicken-4.1.0]$ head eval.c ueval.c ==> eval.c <== /* Generated from eval.scm by the CHICKEN compiler http://www.call-with-current-continuation.org 2009-08-01 00:33 Version 4.0.7 - SVN rev. 15292 linux-unix-gnu-x86 [ manyargs ptables applyhook ] compiled 2009-08-01 on x (Linux) command line: eval.scm -no-trace -optimize-level 2 -include-path . -include-path ./ -explicit-use -output-file eval.c unit: eval */ ==> ueval.c <== /* Generated from eval.scm by the CHICKEN compiler http://www.call-with-current-continuation.org 2009-08-01 00:35 Version 4.0.7 - SVN rev. 15292 linux-unix-gnu-x86 [ manyargs ptables applyhook ] compiled 2009-08-01 on x (Linux) command line: eval.scm -no-trace -optimize-level 2 -include-path . -include-path ./ -explicit-use -unsafe -no-lambda-info -output-file ueval.c unit: eval */
っつう事で、cscに与えたオプションが違うって事ね。頭に"u"が付くほうは、向こう見ずな、 ぶっとび野郎仕様にしてまっせって事だな。ちなみに、どんなぶっ飛び野郎が居るかというと
[sakae@fb ~/chicken-4.1.0]$ ls u*.c udata-structures.c uposixunix.c usrfi-4.c ueval.c uposixwin.c usrfi-69.c uextras.c uregex.c utcp.c ufiles.c usrfi-1.c utils.c ulibrary.c usrfi-13.c utils.import.c ulolevel.c usrfi-14.c uutils.c uports.c usrfi-18.c
重たい処理用に、用意されてるのね。納得しました。
そんじゃ、hello.scmから作ったhello.cも何か、ヒントっぽい事が書かれているかな? ただで見られるんだから、見なけりゃ損だよ!
[sakae@fb ~/work]$ head hello.c /* Generated from hello.scm by the CHICKEN compiler http://www.call-with-current-continuation.org 2009-09-30 02:56 Version 4.1.0 - SVN rev. 15292 freebsd-unix-gnu-x86 [ manyargs dload ptables applyhook ] compiled 2009-09-17 on fb.kuma.net (FreeBSD) command line: hello.scm -optimize-level 3 -output-file hello.c used units: library eval data_structures ports extras srfi_69 */
見といて正解だね。used units: に注目。これって、先ほど、苦労して関数の定義場所を 見つけて、コンパイルの対象にしたファイルじゃん。最初から、ここを見れば良かったのね。
と言う事で、汎用のMakefileをでっち上げてみました。このMakefileを使って、fib.scmの 本家独立版を作ってみます。
# For standalone from chicken .SUFFIXES: .scm .c SRC = fib.c OBJS = runtime.o library.o eval.o expand.o extras.o data-structures.o ports.o srfi-69.o $(SRC) CFLGS = -static -Os -fomit-frame-pointer RUNME: $(OBJS) gcc $(CFLGS) -o $@ $(OBJS) -lm strip $@ .c.o: gcc $(CFLGS) -c $< .scm.c: chicken $< -optimize-level 3 -output-file $@
コンパイルして、実行します。
[sakae@fb ~/work]$ make gcc -static -Os -fomit-frame-pointer -c runtime.c gcc -static -Os -fomit-frame-pointer -c library.c gcc -static -Os -fomit-frame-pointer -c eval.c gcc -static -Os -fomit-frame-pointer -c expand.c gcc -static -Os -fomit-frame-pointer -c extras.c gcc -static -Os -fomit-frame-pointer -c data-structures.c gcc -static -Os -fomit-frame-pointer -c ports.c gcc -static -Os -fomit-frame-pointer -c srfi-69.c chicken fib.scm -optimize-level 3 -output-file fib.c gcc -static -Os -fomit-frame-pointer -o RUNME runtime.o library.o eval.o expand.o extras.o data-structures.o ports.o srfi-69.o fib.c -lm strip RUNME [sakae@fb ~/work]$ ./RUNME 9227465 9.366 seconds elapsed 0.063 seconds in (major) GC 0 mutations 614 minor GCs 29 major GCs
普通にcscでコンパイルしたよりは速くなりました。爆速モードへとコンパイル出来るのだろうか? ちょいと調べた限りでは、分家させちゃうと、本家の威光が及ばないっぽいので、そんなの無理 が、今の所の結論。
で、ふとした事からomit frame pointerなんて 言うページに行き着いた。chickenの出力がCのソースなら後残された道は、(g)ccに頼るしか 無い。オプションを見直そうと言う戦略。真面目にやると糞CPUの糞さ加減に付き合うはめに なりそうなので、何事も控えめに では、ありますが。
それより、目下の悩み所は、MinGW上で作ったchickenで、上のスタテック版を実行すると、M$へ 言いつけちゃうぞアラートが出てしまって、どうしようもない事です。例の「XXはreadに なりませんでした」と言う、役に立たないエラーが出てくるんだな、こうなったら、ブラジルの 開発者に通報する鹿。
奴らラテン系だから、「ヘィ、日本のおにーちゃん、まだ、糞のOSでごにょごにょかい! そん なの早く捨ててしまいな! パラダイスはLinuxだぜぃ」とか、軽く言われそうだな。