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に書いてあるのかな。