retro
unixの故郷と言えば、言わずと知れたAT&Tの研究機関であるベル研。そんなベル研の栄光と 衰退を描いた書籍が出てた。 『世界の技術を支配するベル研究所の興亡』(文藝春秋) 400ページを超える大著ながら、unixに 言及してたのはたった3行だけ。
そんじゃ、後のページは?と言うとネタばれになりそうなんで、、、、って書くと怒られそう なんで。
トランジスターは、固体物理学者ショックレーの元で研究してた、ブラッティン、バーディーンが 点接触形のものを発見。嫉妬に狂ったショックレーはホテルに篭って、接合型のトランジスタ 論文を執筆。この3人は、後世、トランジスタの発明者とされている。こんな話、初めて 聞いたよ。
数学者シャノンはベル研で情報理論を研究。デジタル通信の緒を開いた。PCM通信とかに 発展していくんだな。シャノンはお手玉とか一輪車が大好きだったらしい。お手玉の協会に も入って、いろいろ研究し膨大な資料を作ったけど、まだ発表には不十分という事で、発表 される事は無かったそうな。どこか常人とは違うな。
ベル研で産声を上げた技術は非常に多い。海底通信ケーブルしかり、衛星通信しかり、携帯電話の元となるセルラー 方式しかり、デジカメの眼CCDしかり、光ファイバーとそれにかかせないレーザーしかり。
こういうものを次々に生み出すには、知の結集が必要。そして、長期の展望を見据えての 研究が必要。これには、膨大な資金が必要。電話回線の独占したAT&T、その設備製造を 請け負ったウェスタン・エレクトリック。ここから資金を調達。およそ通信に関する 研究って言うと、予算が通ったらしい。
日本にもこの構図がありましたな。日本電信電話公社がAT&Tに相当。WEに相当するのは、NECとかに なるかな。ベル研に相当するのは、武蔵野通研とか横須賀通研かな。電子交換機という コンピュータの開発関連で、TAOとかもそうなのかな。
AT&Tは、独禁法違反って言う事で司法省に眼を付けられ、分割。それが遠因になって 衰退モード突入。もう、金に糸目をつけぬ研究って無理なんでしょうかね?
ぐぐるとかあぷるとかは、ベル研の技術配当で食べてるようにしか見えないな。
gforthのdebugger
gforhのマニュアルを見ていたら、debuggerが有るよって書いてあった。さすが、デファクト・スタンダードに なるだけあるな。どんなものか触ってみる。但し、普通?のgforthには実装されていない ようで、gforth-itcを使う必要が有ります。まあ、TPOをわきまえてgforthを使えって 事だな。
[sakae@fedora gforth-0.7.2]$ gforth-itc Gforth 0.7.2, Copyright (C) 1995-2008 Free Software Foundation, Inc. Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license' Type `bye' to exit : fib ( n1 -- n2 ) compiled dup 2 < if compiled drop 1 compiled else compiled dup compiled 1- recurse compiled swap 2 - recurse compiled + compiled then ; ok 3 dbg fib : fib Scanning code... Nesting debugger ready! [ 1 ] 00003 28834938 8055C9C dup -> [ 2 ] 00003 00003 2883493C 8055B30 2 -> [ 3 ] 00003 00003 00002 28834944 8055BE0 < -> [ 2 ] 00003 00000 28834948 8055AAC IF -> [ 1 ] 00003 28834964 8055C9C dup -> [ 2 ] 00003 00003 28834968 8055B4C 1- -> [ 2 ] 00003 00002 2883496C 8055A88 fib -> [ 3 ] 00003 00002 00001 28834974 8055C98 swap -> [ 3 ] 00003 00001 00002 28834978 8055B30 2 -> [ 4 ] 00003 00001 00002 00002 28834980 8055B40 - -> [ 3 ] 00003 00001 00000 28834984 8055A88 fib -> [ 3 ] 00003 00001 00001 2883498C 8055B34 + -> [ 2 ] 00003 00002 28834990 8055A94 THEN ; -> ok
リターンキーを叩くと、1stepづつ実行してくれる。秋田ら、sキーとかで実行を終了出来る。
ソースにbreakpointを埋め込んでおいて、そこで止める事も出来る。
: fact ( n -- n! ) recursive dup 0> if dup 1- fact * else break: drop 1 endif ; 5 fact CR . CR
こんなfact.fsを作っておいて、このファイルを喰わせてみる。break: の所で、debuggerが 起動してくる。
[sakae@fedora gforth-0.7.2]$ gforth-itc fact.fs Scanning code... <134525094> <0> Nesting debugger ready! [ 6 ] 00003 00002 00001 00000 B73FD55C 8056434 drop -> [ 5 ] 00004 00003 00002 00001 B73FD560 80562D0 1 -> [ 6 ] 00003 00002 00001 00001 B73FD568 8056234 THEN ; -> 120 Gforth 0.7.2, Copyright (C) 1995-2008 Free Software Foundation, Inc. Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license' Type `bye' to exit
ふむ、ファイルを喰わせるとそれを実行した後、replに入るのだな。何かの時にこの挙動は 使えそうだな。覚えておこう。
retro
前回見つけたforth色々サイトに中に、retroなんてのが有った。復古調って意味なんだな。 gforthは、現在進行形で気を抜けないけど、おいらみたいな昭和の人には、のんびりが 案外合っているかも知れんな。そんな訳で、のーーーーんびりと行きます。
retroへ行き、tar玉を取ってきて展開し、make一発で、あっという間に、retroが出来上がります。
[sakae@fedora retro-11.5]$ ./retro Retro 11.5 ok words describe types' needs :needs __^ strings' buffer' internals' variables| doc{ yield later getEnv delay time include :include getNumber getToken bye save words .s reset depth formatted " __" tempString rename: with| findInChain global without with :with ;chain chain: .chain <%> %% dicts __' __% __# __$ parsing .parse putn space clear toString binary octal hex decimal elements allot string: constant variable variable: within if; ahead fill copy each@ <each@> iter iterd times whend when preserve cons tri@ tri* tri bi@ bi* bi take curry until while [] jump: ` compile-only immediate .compiler __2 __- __+ __! __@ __& reclass: reclass hide :hide xt->d d' HEADERS default: is devector }} ---reveal--- {{ ?dup -- ++ -! +! tuck rot nip :doc tabAsWhitespace build version update base eatLeading? remapping which heap ch cw memory fh fw fb compiler last listen ok notFound <notFound> ' find boot isNumber? toNumber numbers atib :is :devector keepString withLength getLength compare > < <= >= != <> == = sip dip ifFalse ifTrue if ] [ ( : ]] [[ create header d->name d->doc d->xt d->class accept getc keymap:handler getc:with/remap getc:unfiltered remap:whitespace remapKeys tib STRING-BUFFERS STRING-LENGTH keymap:TABLE keymap:PREFIX keymap puts <puts> cr putc redraw again repeat 0; pop push ; ;; here !+ @+ do negate mod / off on not over wait in out >> << /mod * - + ! @ xor or and drop swap 1- 1+ dup .primitive .data .macro .word withClass , ok
使えるワードも標準では上記ぐらいだし、楽そう。勿論、ライブラリィーを追加 出来るけどね。
ok needs docstrings` ok chain: docstrings' ok : describe ( string:documentation string:name - ) find drop [ keepString ] dip !d->doc ; ok : help ( string:name - ) find drop @d->doc 0; cr puts cr ; ok ;chain
詳しい使い方は、 Retro 言語で公開されて います。また、retroを動かしている仮想マシンの仕様は、 Ngaroと言うそうで、仕様が解説されてました。
ちょいとretroを動かした時、どれぐらいのステップが実行されるかは、次のようにして 調べられます。
[sakae@pcbsd ~/src/retro]$ ./retro --stats : ok bye Runtime Statistics NOP: 0 LIT: 6362869 DUP: 10355248 DROP: 3890673 SWAP: 2477970 PUSH: 4545800 : CALL: 8240034 Max SP: 14 Max RSP: 52 Total opcodes processed: 65743563
Many VM
The VM って書きたいけど、唯一無二じゃなくて、いろいろな言語で実装された博覧会の 様相を呈している。
完全版では、
[sakae@pcbsd ~/src/retro/vm/complete]$ wc retro.* lisp/ngaro.lisp 778 2284 20008 retro.c 657 1658 16471 retro.cs 201 1209 7412 retro.fsx 592 1939 15877 retro.php 477 1706 11888 retro.py 411 1475 10389 retro.rb 196 983 6487 retro.rx 866 2212 14996 retro.s 323 1314 12390 lisp/ngaro.lisp
この他にも、go版が有ったけど、ざっと見た限りでは、ファイルが分割されてて面倒なので 省略。retro.fsxって行数がやけに少ないけど、これは何者? どうもML系っぽいな。 そして、極めつけは、retro.rx。なんと、自分自身の言語で書いてあるよ。これ、どうやって 動かすの?
[sakae@pcbsd ~/src/retro/vm]$ wc partial/* 260 1338 7988 partial/retro.fs 442 1308 9037 partial/retro.java 330 1457 8657 partial/retro.lua 336 985 7169 partial/retro.pl 306 840 7233 partial/retro.scm
こちらは、不完全版とでも考えたらいいのでしょうか。ML系、短いなあ。
[sakae@pcbsd ~/src/retro/vm]$ ls embedded/ arm avr pic32
なんと、picとかでも動くってさ。こりゃ、LL祭りどこの騒ぎじゃありませんよ。 そして、Javascript版も有って、ブラウザーからも実行出来る。完全にLL版の範疇を超えているぞ。
benchmarks
これだけ色々なVMが有ると、ベンチしたいなーってのが心情。そんなおいらの気持ちを 知ってか知らずか、作者さんは、ちゃんと用意してくれてる。いろいろなベンチが あるけど、シンプルなやつを選んでみた。
[sakae@pcbsd ~/src/retro/benchmarks]$ cat loop.rx : bar 100 [ 100 [ 1000 [ ] times ] times ] times bye ; &bar is boot save bye
100*100*1000回、空ループを回すってやつ。これをmake loopsして、イメージファイルを 作っておく。そして、まずはCで書かれたvmを試してみる。
[sakae@pcbsd ~/src/retro]$ time ./retro --image benchmarks/retroImage real 0m4.426s user 0m4.390s sys 0m0.000s
次はrubyバージョンのvm
[sakae@pcbsd ~/src/retro]$ make ruby cp vm/complete/retro.rb retro chmod +x retro [sakae@pcbsd ~/src/retro]$ ruby -v ruby 1.9.3p429 (2013-05-15 revision 40747) [i386-freebsd9] [sakae@pcbsd ~/src/retro]$ cd benchmarks/ [sakae@pcbsd ~/src/retro/benchmarks]$ time ../retro real 3m6.232s user 3m3.379s sys 0m1.395s
次はPython版
[sakae@pcbsd ~/src/retro]$ make python cp vm/complete/retro.py retro chmod +x retro [sakae@pcbsd ~/src/retro]$ python --version Python 2.7.3 [sakae@pcbsd ~/src/retro]$ cd benchmarks/ [sakae@pcbsd ~/src/retro/benchmarks]$ time ../retro real 2m48.092s user 2m46.426s sys 0m0.273s
sbcl版も有ったので
[sakae@pcbsd ~/src/retro]$ make sbcl ( cd vm/complete/lisp && sbcl --no-sysinit --no-userinit --noprint --load sbcl.lisp ) This is SBCL 1.1.8, an implementation of ANSI Common Lisp. : [sakae@pcbsd ~/src/retro]$ cd benchmarks/ [sakae@pcbsd ~/src/retro/benchmarks]$ time ../retro real 0m4.719s user 0m4.658s sys 0m0.040s
Cで書いたvmと遜色が無いな。違いが有るのは、出来上がったバイナリーのサイズ。sbcl版の retroは、呆れるぐらい巨大だったぞ。まあ、いろいろ背負っているからね。
後、goを入れてやってみた。指示に従ってコンパイルすると、bin/mainが出来上がるので、 それを所定の位置に移動。
[sakae@pcbsd ~/src/retro/benchmarks]$ time ../main real 0m2.210s user 0m2.157s sys 0m0.042s
えっ、Cより速いなんてにわかには信じられんな。ベル研の末裔のマジックなんだろうか? goを作った人は昔ベル研でCを作った。Cなんて言う変な名前はB言語の次だからCにしたって 有名な話がある。この人、ベル研やめてぐぐるに入って、ぐぐるに捧げるって事で、googleから 頭2文字を頂いて、go ってしたんだな。名前なんて、仮の姿なんだよ。だから、こだわる 必要ないよって態度なんかな。やっぱり天才は違うな。
ああ、トランジスタを発明したショックレーもベル研を卒業して、西海岸に移動。自分の 会社を興している。ご他聞に漏れず、優秀なやつを連れてったんだな。しかし、学者さんに 経営の才はなく、部下達が独立して自分で半導体会社を立ち上げた。それが、フィアチャイルドで あり、テキサス・インスツルメンツでありインテルである。今の半導体会社のルーツは、 ショックレー学校のドロップアウトした連中なんだな。有名な人として、インテルのムーア さんがいるな。
話が逸れた。goマジックがループだけにしか通じないか、他のテストもやってみる。例に よってfactです。retroでは、こんな風に書かれていた。
[sakae@pcbsd ~/src/retro/benchmarks]$ cat fact.rx : <factorial> dup 1 = if; dup 1- <factorial> * ; : factorial dup 0 = &1+ &<factorial> if ; : foo 100000 [ 15 factorial drop ] times 15 factorial putn bye ; &foo is boot save bye
[sakae@pcbsd ~/src/retro/benchmarks]$ make factorial [sakae@pcbsd ~/src/retro/benchmarks]$ time ../retro 2004310016 real 0m0.802s user 0m0.794s sys 0m0.004s [sakae@pcbsd ~/src/retro/benchmarks]$ time ../main 2004310016 real 0m0.540s user 0m0.513s sys 0m0.017s
うん、素晴らしい仕事をしてますな。おまけで、fibも有ったので。
[sakae@pcbsd ~/src/retro/benchmarks]$ make fib [sakae@pcbsd ~/src/retro/benchmarks]$ time ../retro real 0m6.831s user 0m6.783s sys 0m0.005s [sakae@pcbsd ~/src/retro/benchmarks]$ time ../main real 0m4.202s user 0m4.135s sys 0m0.024s
このC言語より断トツにgoの方が速いって成果は何処から出てくるの? もしかしてFreeBSDと goの相性が最高に良いから。舞台をLinuxに移しても、同様な結果になるの? それとも、goが昔設計したCの弱点を知り尽くした生みの親によって才設計されたから?
詳しい事は、 golangに書いてあるのかな。