ecl (4)

歴史物を読んでいると大体時代設定は、維新の頃か織田、豊臣の頃が多いように思う。 ロマンに満ちているんでしょうなあ。NHKの日曜夜8時も一緒だ。先回りして真田本でも 読んでみるか。

大体、天下統一とか地所の侵食の話。現代は、領海の侵食で南の海が危うい状態になって いたりする。人間の業だなあ。この日本において、ドンパチやる訳にもいかないので、 それぞれの業界において地所の取り合いをやっている。かっこよく言うと、資本主義社会における 自由競争って訳です。

平民を広告で洗脳して、売りつけようって算段。で、各業界でどんな会社が覇権を握って いるかという本が出てた。『見るだけですっきりわかる業界地図』2300社程が載ってたぞ。裏『会社四季報』ですな。

色々な業界でどの会社が強いか。たとえば、建設業界だと、鹿島、清水建設、大林組、大成建設、 竹中工務店あたりが、100万石大名ならぬ、売り上げ1兆円規模の会社みたい。もし株を 買って応援しようってんなら、これらの会社がどんな儲け話に首を突っ込んでいるかなんて、 将来性もさりげなく紹介されてて、投資指南書のようにも見えるな。

スカイツリー竣工の大林組は、台湾で野球ドームとか、大成建設はハノイの空港ターミナルを 手がけるですって。活路はやはり外国に求めるしか無いんでしょうな。

いやいや、東京オリンピックがあるじゃないって話もあるじゃん。箱を作るのもいいけど、 日本のおもてなしも大事。ってんで、オリンピック協会公認を狙う、ゴム業界はどうだ。 別に、応援にゴム風船ってんじゃなくて、衛生ゴム。日本企業の特殊技術がきっと世界の 絶賛をあびるに違いない。この分野での3強は、オカモト、不二ラテックス、相模ゴム工業 らしいですぜ。とかなんとか、以外な会社が出てきたりして面白かったよ。

所で、この所読書にも熱が入っているので、読書メーターでも付けてみるかな。 毎回読んだ本を上げていくと尼からお勧めが来るんで、分類コードで誤魔化してみるか。

えと、分類と言えば、 図書分類法 とか 日本十進分類法 が、手がかりになるかな。でも、借りてきてる本に貼ってあるラベルは、これに則って いないようだ。図書館の整理がし易いように特殊な分類をしてるみたい。

諦めて、 ISBNコードでもいいかな。これだと簡単に 整理用のDBとかが構築出来そうだな。実践顧問リスプ本にも、同じような趣旨で、CD目録を 作る例が出てたから、参考になるかも。

出来上がるまで、簡単にメモしとく。

6冊 / 1823頁 / 11152円

今回は、これだけ楽しめました。そうそう、メータに表示してある、総ページ数とか 合計金額はLisperらしくLispなりschemeで計算しましょう。これらを入れてなければ、emacs でもいいぞ。emacsはとても大きな数(整数)の計算は出来ないけど、庶民が扱う数字ぐらいなら お茶の済々ですよ。なお、bcとかだと、いちいち足し算記号を 入れるのが面倒ですから。

sakae@uB:~$ gosh
gosh> (+ 205 351 237 356 242 432)
1823

time macro

前回からのprofileでBUGっぽい挙動。調べるのはいいんだけど、その前に予備知識として timeマクロに当たっておく。eclのコードでは、src/lsp/mislib.lspに収録されてた。 boehm-gcの有る無しによって、若干コードが違うけど、こんなのだ。

  (let* ((real-start (get-internal-real-time))
         (run-start (get-internal-run-time))
         gc-start
         bytes-consed
         real-end
         run-end
         gc-end)
    ;; Garbage collection forces counters to be updated
    (si::gc t)
    (setf gc-start (si::gc-time))
    (multiple-value-prog1
        (funcall closure)
      (setq run-end (get-internal-run-time)
            real-end (get-internal-real-time)
            gc-end (si::gc-time))
      (format *trace-output*
             "real time : ~,3F secs~%~
              run time  : ~,3F secs~%~
              GC time   : ~,3F secs~%"
             (/ (- real-end real-start) internal-time-units-per-second)
             (/ (- run-end run-start) internal-time-units-per-second)
             (/ (- gc-end gc-start) internal-time-units-per-second))))

実行前にメーターの値を読んでおき、実行後もメーターの値を読む、差分を取って、 メータの一目盛りで正規化して、出力って寸法。internal-time-units-per-secondって どこかに定義されてるかと思ったけど、見当たらないので、eclに聞いてみる。

> internal-time-units-per-second

1000

一秒間に1000カウントするんだ。分解能が1msって事だな。所で、get-internal-run-timeって、 どうやって取り出してるの? reall-timeってのは、大体想像付くけど、run-timeの方は、 さっぱりだ。まあ、システムコールを発してはいるんだろうけど。

システムコールなら、そんなのstraceすれば一発じゃんって事になるけど、それじゃつまらないので、 gdbを使ってみる。

システムコールが発せられそうな所で止めて、近辺を調べればOK。

sakae@deb:~/ecl-13.5.1/src$ grep get-internal-run-time `find . -type f`
./cmp/proclamations.lsp:(proclamation get-internal-run-time () unsigned-byte :no-side-effects)
./doc/help.lsp:(docfun get-internal-run-time function () "
./lsp/mislib.lsp:        (run-start (get-internal-run-time))
./lsp/mislib.lsp:      (setq run-end (get-internal-run-time)
./lsp/mislib.lsp:         run-start (get-internal-run-time))
./lsp/mislib.lsp:      (setq run-end (get-internal-run-time)

あれ、引っかかってこないぞ。何故?て、10秒考えたら、Lisp語とC語の違いに思い出したよ。 lisp語は、平気で "-" を使って単語を繋げていくけど、C語ではそんな事を許していない。 よって、C語だとダッシュ記号をアンダーバーに置き換えるのが普通。 (単語の頭を大文字にする流派もあるけど、それをLispでやると平気で4こぶのラクダが 誕生したりする。そんなの、扱いづらいと言うか読みづらいぞ。)

sakae@deb:~/ecl-13.5.1/src$ grep get_internal_run_time `find . -type f`
./c/symbols_list.h:{"GET-INTERNAL-RUN-TIME", CL_ORDINARY, cl_get_internal_run_time, 0, OBJNULL},
./c/symbols_list2.h:{"GET-INTERNAL-RUN-TIME","cl_get_internal_run_time"},
./c/time.d:ecl_get_internal_run_time(struct ecl_timeval *tv)
./c/time.d:     ecl_get_internal_run_time(&tv);
./c/time.d:cl_get_internal_run_time()
./c/time.d:     ecl_get_internal_run_time(&tv);
./h/external.h:extern ECL_API cl_object cl_get_internal_run_time(void);
./h/internal.h:extern void ecl_get_internal_run_time(struct ecl_timeval *time);

もう答えが出ちゃったけど、gdbを使いたいので、あえて使ってみる。きっと良い事が 有るでしょう。ああ、gdbを使う時は、emacsからだと何かと便利。buildに移動して emacsを起動、そこから、M-x gdb して、問いにecl_minと指定。

(gdb) b ecl_get_internal_run_time
Breakpoint 10 at 0x809f400: file /home/sakae/ecl-13.5.1/src/c/time.d, line 76.
(gdb) run
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".
[New Thread 0xb7e2eb70 (LWP 2491)]
;*** Lisp core booted ****
ECL (Embeddable Common Lisp)

> (get-internal-run-time)

これで、breakして、該当のソースも表示された。GETRUSAGEを持ってる場合は、これを 使え、マイクロソフトの場合はああしろとかコードを切り分けている。

  void
  ecl_get_internal_run_time(struct ecl_timeval *tv)
B =>
  #ifdef HAVE_GETRUSAGE
          struct rusage r;
          getrusage(RUSAGE_SELF, &r);
          tv->tv_usec = r.ru_utime.tv_usec;
          tv->tv_sec = r.ru_utime.tv_sec;
  #else
    :

config.hをみると、HAVE_GETRUSAGEが1になってるんで、(or、STEP実行でもいいけど) getrusageが使われ事が分かる。こやつは何ぞや。manを引くと

           struct rusage {
               struct timeval ru_utime; /* user CPU time used */
               struct timeval ru_stime; /* system CPU time used */
                  :
       ru_utime
              This  is  the total amount of time spent executing in user mode,
              expressed in a timeval structure (seconds plus microseconds).

       ru_stime
              This is the total amount of time spent executing in kernel mode,
              expressed in a timeval structure (seconds plus microseconds).

ふーん、了解しました。ユーザーモードで走った時間なのね。こいつの分解能はマイクロ秒 だけど、そんなに細かく表示したって意味ないんで、どこか上の方の階層で丸めているんだな。

そういう疑問はどんな経路で、ここまで来たかを押さえておくと、点検する範囲を狭められるので 便利だぞ。ちょいと経路を調べておく。

(gdb) bt
#0  ecl_get_internal_run_time (tv=tv@entry=0xbffff388) at /home/sakae/ecl-13.5.1/src/c/time.d:76
#1  0x0809f6eb in cl_get_internal_run_time () at /home/sakae/ecl-13.5.1/src/c/time.d:217
#2  0x080c153e in APPLY_fixed (n=0, fn=0x809f6d0 <cl_get_internal_run_time>, x=x@entry=0x8351004) at /home/sakae/ecl-13.5.1/src/c/apply.d:350
#3  0x0805c479 in ecl_interpret (frame=frame@entry=0xbffff5c0, env=0x1, bytecodes=bytecodes@entry=0x8322fa0) at /home/sakae/ecl-13.5.1/src/c/interpreter.d:493
#4  0x080610e2 in eval_nontrivial_form (form=<optimized out>, env=0xb7fde000) at /home/sakae/ecl-13.5.1/src/c/compiler.d:2374
#5  eval_form (env=env@entry=0xb7fde000, form=form@entry=0x831f5e1) at /home/sakae/ecl-13.5.1/src/c/compiler.d:2388
#6  0x08062c70 in si_eval_with_env (narg=narg@entry=1, form=0x831f5e1) at /home/sakae/ecl-13.5.1/src/c/compiler.d:3129
#7  0x0804eab8 in si_simple_toplevel () at /home/sakae/ecl-13.5.1/src/c/cinit.d:173
#8  0x08083c55 in dispatch0 (narg=0) at /home/sakae/ecl-13.5.1/src/c/cfun_dispatch.d:10
#9  0x0804e8f2 in main (argc=1, args=0xbffff7c4) at /home/sakae/ecl-13.5.1/src/c/cinit.d:203

後は、この階層を登ったり下りたりしながらソースに当たればOK。階層を2つupしたら、 APPLY_fixedに到着。これって、アリティーによって呼び出し方法を変えてる。一体幾つまで アリティーが採れるか確認したら、64までOKで、それ以上は、引数の数が多すぎますって エラーに落ちるようになってた。こういう数も委員会LISPではきちんと決めてるんかね。 それに違反すると、CLとは、名乗ってはいけないとか。

まあ、このあたりは見所が一杯あるので、観光気分に浸っておこう。ガイドは、上でgrepした時に 出てきたsymbols_list.hあたりが良いのかな。

cl_symbol_initializer
cl_symbols[] = {
{"CAR", CL_ORDINARY, cl_car, 1, OBJNULL},
{"LIST", CL_ORDINARY, cl_list, -1, OBJNULL},
{"CONS", CL_ORDINARY, cl_cons, 2, OBJNULL},
{"TIME", CL_ORDINARY, NULL, -1, OBJNULL},

ふむ、対応表だな。一番左側がユーザーに見えるLisp上の関数名、次は属性かな、次はC語で 書かれていたらその関数名、NULLはマクロって事か、次の数字は引数の数、マイナスは不定長、 最後は、値が既に定まっている場合(定数だな)には、その値。

属性は、all_symbols.dに登録されてた。こんな具合。

#define CL_ORDINARY     CL_PACKAGE | ORDINARY_SYMBOL
#define CL_SPECIAL      CL_PACKAGE | SPECIAL_SYMBOL
#define CL_CONSTANT     CL_PACKAGE | CONSTANT_SYMBOL
#define CL_FORM         CL_PACKAGE | ORDINARY_SYMBOL | FORM_SYMBOL
#define SI_ORDINARY     SI_PACKAGE | ORDINARY_SYMBOL
#define SI_SPECIAL      SI_PACKAGE | SPECIAL_SYMBOL
 :

これらシンボルの戸籍簿を登録してる所が、all_symbols.d だ。

観光ガイドに従って、consで止まってもらおうとしたら、止まらずに変な所に案内された。 プロンプトで入力したもののうち、選りすぐったものは、その場でコンパイルしてから 実行してるみたい。その優等生は、compiler.dの中のdatabaseってい所に登録されてる みたい。

余り深入りすると、変な奴に捕まりそうなので、程ほどにして次行きます。

asdf

profileの探求なんだけど、生憎パッケージになってて、手出しが難しそう。そういう時は 自分の陣地に引き寄せて、いたぶるのが正しい処世術だと思うぞ。

このprofileは、eclをコンパイルした時に作られるけど、buildの中には、profile.asdってのも 鎮座してた。という事は、asdfで単独コンパイルとか出来るんじゃねぇ?

でも、asdfの操り方なんて知らないし。。例が出てた。2つのファイルをコンパイルして 合体させ、最後は単独実行出来るようにするやつ。

sakae@deb:~/ecl-13.5.1/examples/asdf$ ls
example.asd  file1.lisp  file2.lisp  readme.lisp

example.asdってのは、asdfシステムが使うMakefile相当品らしい。file1,2は普通のやつ。readme.lisp ってのが、asdfを操る、shellファイルみたいだ。よって、これらをぱくってきて、何とか ならないか、なんとかしてみる。

profile.lispをかっぱらってきて、パッケージ名を取り合えず、mineと改名したよ。 それから、asdファイルは、必要最低限にした。

sakae@deb:~/src/sa$ cat mine.asd
(DEFSYSTEM :mine
    :COMPONENTS ((:file "mine" )))

問題のreadme.lispも必要そうなものだけにした。

(require :asdf)
(require :cmp)

(setf *load-verbose* nil)
(setf *compile-verbose* nil)
(setf c::*suppress-compiler-warnings* t)
(setf c::*suppress-compiler-notes* t)

(setf c::*compile-in-constants* t)

(push (make-pathname :name nil :type nil :version nil
                     :defaults *load-truename*)
      asdf:*central-registry*)
 
(trace c::builder)

(asdf:make-build :mine :type :fasl :move-here "./zz")

必要なのは最後の行だけで良さそうだけど、素直に現状維持でやってみる。

sakae@deb:~/src/sa$ ecl -load readme.lisp
;;; Loading "/home/sakae/src/sa/readme.lisp"
;;; Loading #P"/usr/local/lib/ecl-13.5.1/asdf.fas"
 Building FASL file 'mine.fas'
;;; Compiling (DEFVAR *PROFILE-LOCK* ...).
;;; Compiling (DEFUN GET-BYTES-CONSED ...).
;;; Style warning:
;;;   in file mine.lisp, position 2075
;;;   at (DEFUN GET-BYTES-CONSED ...)
;;;   ! Variable +WRAP+ was undefined. Compiler assumes it is a global.
;;; Compiling (DEFVAR *PROFILED-FUN-NAME->INFO* ...).
;;; Compiling (DEFSTRUCT (PROFILE-INFO #) ...).
      :
;;; Emitting code for GET-BYTES-CONSED.
;;; Emitting code for MAKE-PROFILE-INFO.
;;; Emitting code for MAKE-OVERHEAD.
       :
1> (C::BUILDER :FASL #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine-ASDF-TMP.fas" :LISP-FILES (#P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.o"))
<1 (C::BUILDER #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine-ASDF-TMP.fas")
1> (C::BUILDER :LIB #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.a" :LISP-FILES (#P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.o") :INIT-NAME "init_lib_MINE" :PROLOGUE-CODE NIL :EPILOGUE-CODE (PROGN     NIL))
<1 (C::BUILDER #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.a")
1> (C::BUILDER :FASL #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.fasb" :LISP-FILES (#P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.o"   #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.a") :INIT-NAME "init_fas_CODE" :PROLOGUE-CODE NIL :EPILOGUE-CODE (PROGN NIL))
<1 (C::BUILDER #P"/home/sakae/.cache/common-lisp/ecl-13.5.1-unknown-linux-x86/home/sakae/src/sa/mine.fasb")

これで、キャッシュの深い所に、mine.fasが出来てた。ひょっとして動くんでないかい? 今後の事も考えて、自動化をしとく。

sakae@deb:~/src/sa$ cat run.lisp
;;(delete-file "./zz/mine.fasb")
(ext:system  "rm -f ./zz/mine.fasb")  ;不用ファイル削除
(require :asdf)
(load "readme.lisp")                    ; コンパイル
(require :mine)
(mine:report)
(load "cup.lisp")                       ; 被測定物
(mine:profile tak lg)
(tak 12 6 0)
(lg)
(mine:report)

実行結果

sakae@deb:~/src/sa$ ecl -load run.lisp
   :
Measuring PROFILE overhead..done
  seconds  | consed | calls |  sec/call  |  name
----------------------------------------------------
----------------------------------------------------
     0.000 |      0 |     0 |            | Total

estimated total profiling overhead: 0.00 seconds
overhead estimation parameters:
  6.4000005e-8s/call, 1.344e-6s total profiling, 4.32e-7s internal profiling
  seconds  |  consed |  calls |  sec/call  |  name
------------------------------------------------------
     0.528 |         0 |      1 |   0.527999 | LG
     0.000 | 4,577,344 | 63,609 |   0.000000 | TAK
--------------------------------------------------------
     0.528 | 4,577,344 | 63,610 |            | Total

estimated total profiling overhead: 0.01 seconds
overhead estimation parameters:
  6.4000005e-8s/call, 1.344e-6s total profiling, 4.32e-7s internal profiling
   :
> (time (tak 12 6 0))

real time : 0.282 secs
run time  : 0.192 secs
gc count  : 1 times
consed    : 49493496 bytes
1

おお、takは駄目だけど、lgとか言う、算数のドリルはちゃんと時間を測ってくれているな。

(defun lg ()  (dotimes (i 2000000) (1+ i)))

考えるに、takってのは、あの竹内先生が考案したんで、takって名前で流通してるんだけど、 元は日本の役所のお家芸、たらい回しが源流だ。たらい回しだから、さっぱり時間が かからんって事かね。takの内部は、引き算しながらたらいを回してるんだけどね。

こういう時は、系統が違うsbclででもやってみる鹿。(sbclはCMUCLから分家してるんで、 profile資産は、そのまま継承してるかもな。)

CL-USER> (tak 12 6 0)
  seconds  |   consed  |  calls |  sec/call  |  name
--------------------------------------------------------
     0.480 |         0 |      1 |   0.480000 | LG
     0.027 | 4,579,296 | 63,609 |  0.0000004 | TAK
--------------------------------------------------------
     0.507 | 4,579,296 | 63,610 |            | Total

estimated total profiling overhead: 0.01 seconds
overhead estimation parameters:
  7.4e-8s/call, 1.32e-7s total profiling, 1.1e-7s internal profiling

These functions were not called:
 ADD1 FACT SQ
1
CL-USER> (time (tak 12 6 0))
real time : 1.148 secs
run time  : 0.033 secs
gc count  : 1 times
consed    : 4577688 bytes

ちゃんと求まっているなあ。はて、どうしたものかな? 暫く考えてみよう。

息抜きにネットをうろうろしてたら、 #9LISP How to use ASDF なんてのに出会った。こういう先駆者が居ると助かるなあ。

/usr/bin/time

前の方でやった、timeマクロはCLの要件として必ず備え付けられているけど、これの 元祖は何よ? 普通にshellのプロンプトからtimeってやると、bash備え付けのやつが 動くけど、正式には、/usr/bin/timeあたりが、由緒あるやつ。乗りかかった船と思って ソースを覗いてみる。FreeBSDなら、 /usr/src/usr.bin/time/time.c にあるぞ。

        (void)gettimeofday(&before_tv, NULL);
        switch(pid = fork()) {
        case 0:                         /* child */
                execvp(*argv, argv);
        }
        :
        while (wait4(pid, &status, 0, &ru) != pid);
        (void)gettimeofday(&after, NULL);
         :
showtime(FILE *out, struct timeval *before, struct timeval *after, struct rusage *ru)
          :
        after->tv_sec -= before->tv_sec;
        after->tv_usec -= before->tv_usec;
        if (after->tv_usec < 0)
                after->tv_sec--, after->tv_usec += 1000000;
           :
                fprintf(out, "%9jd%c%02ld real ",
                        (intmax_t)after->tv_sec, decimal_point,
                        after->tv_usec/10000);
                fprintf(out, "%9jd%c%02ld user ",
                        (intmax_t)ru->ru_utime.tv_sec, decimal_point,
                        ru->ru_utime.tv_usec/10000);
                fprintf(out, "%9jd%c%02ld sys\n",
                        (intmax_t)ru->ru_stime.tv_sec, decimal_point,
                        ru->ru_stime.tv_usec/10000);

実実行時間は、forkしてからwait4で子供が死ぬまでの時間だな。usr/sys時間は、wait4に 乗って返ってくる課金のための時間か。usrは、ユーザーモードで走った時間、sysはカーネルに お願いして、カーネルモードで走った時間か。こりゃ、時間を誤魔化そうったって無理な相談だな。

で、timeのソースを読んでて、面白いオプションが有る事に気付いた。

[sakae@fb10 ~/src/sa]$ /usr/bin/time -l ecl -shell run.lisp
   :
        7.23 real         1.17 user         3.86 sys
     25816  maximum resident set size
       943  average shared memory size
     22999  average unshared data size
       129  average unshared stack size
      9184  page reclaims
       125  page faults
         0  swaps
        48  block input operations
         1  block output operations
         0  messages sent
         0  messages received
         7  signals received
      8184  voluntary context switches
      2225  involuntary context switches

こういうのを見て、なるべくシステムに負担をかけないエコなappって開発出来るのだろうか? 里奈では、-lに相当するオプションは、-v になってたよ。

ccl

今まで色々なCLを入れてみたけど、世間一般にはどんなやつが人気になってるの? ある調査結果が公表されてた。 Responses to the Quicklisp CL survey Lisperの生態が垣間見れて、興味深いぞ。

ああ、Lisperの生態と言えばLisp人がLispについて思う事を書いてました。 LisperはなぜLispが読みやすいし書きやすいと思うのか? とか、 なぜLispは「括弧が多い」印象になるのか? 本も挙げてくれてます。 読んだ本をなんとなく挙げて見る。(Lisp関係)

で、比較的良く使われている、 Clozure CL でも入れてみるか。万次郎Linuxの所に集積してみた。32Bit用と64Bit用が同時収録されてて、 どちらでもお好きな方をどうぞって態度。

結構DLしたtar球の大きいし、回線が細かったので、2度落とすのも面倒ってんで、tar球を FreeBSDに送り使えるか実験。LispのKernelはOS専用になってるけど、ソースが有るので 簡単にそれぞれのOS用が構築出来る(出来た)。 いざ起動しようとしたら、イメージがLinux用だから、動けんわと文句を言われた。 イメージの統一って、何故出来ぬ?たかがbitの固まりだろうに。と、悪態をつくのでした。

でも、いじけていてもしょうがないので、一応自分用に再buildしてみます。

[sakae@manjaro .ccl]$ scripts/ccl
Welcome to Clozure Common Lisp Version 1.9-r15756  (LinuxX8632)!
? (rebuild-ccl :full t)
    :
;Loading #P"/home/sakae/.ccl/level-0/l0-utils.lx32fsl"...
;Loading #P"/home/sakae/.ccl/level-0/nfasload.lx32fsl"...
;Wrote bootstrapping image: #P"/home/sakae/.ccl/x86-boot32"
;Building lisp-kernel ...
;Kernel built successfully.
;Wrote heap image: #P"/home/sakae/.ccl/lx86cl.image"
NIL
?

LispのKernelであるlx86clも作り変えてくれている。こやつを暴いてみると、専用のlibを 使っていない。という事は、イメージにもろもろの物を押し込んでいるんだな。

と、なればlx86clとlx86cl.imageだけを持ってけば、どこでもCLが出来るのかな。 その前に、出来たやつの動作確認。

[sakae@manjaro .ccl]$ ./lx86cl
Welcome to Clozure Common Lisp Version 1.9  (LinuxX8632)!
? (room)
Approximately 16,646,144 bytes of memory can be allocated
before the next full GC is triggered.

                   Total Size             Free                 Used
Lisp Heap:       20316160 (19840K)   16646144 (16256K)    3670016 (3584K)
Stacks:           6495208 (6343K)     6492852 (6341K)        2356 (2K)
Static:          14682504 (14338K)          0 (0K)       14682504 (14338K)
2084.625 MB reserved for heap expansion.
NIL
? (quit)

うん、動いているな。じゃ、lx86clとそのイメージの2つのファイルをウブに転送。 動作確認はどうすべ? いきなりの試練を与えてみる。swankサーバーは動くのか?

sakae@uB:~/.emacs.d/slime$ ~/.ccl/lx86cl -l start-swank.lisp
   :
; While executing: SWANK-BACKEND::WARN-UNIMPLEMENTED-INTERFACES, in process listener(1).
;; Swank started at port: 4005.
Welcome to Clozure Common Lisp Version 1.9  (LinuxX8632)!
?

サーバーが起動した後、プロンプトが出てるぞ。なんじゃこれ? で、emacsからちゃんとslime-connect 出来たよ。結構、軽めで良い感じ。なんじゃこれは、ひょっとしてスレッドとか申すやつが 動いてるんじゃあるまいか。 どんなスレッドが走っているかslimeから確認出来る ようなので、 M-x slime-selector t してみた。

Id Name                           Status               Priority
12 repl-thread                    Semaphore timed wait 0
11 auto-flush-thread              Sleep                0
6  swank-indentation-cache-thread Semaphore timed wait 0
5  reader-thread                  Active               0
4  control-thread                 Semaphore timed wait 0
2  Swank Sentinel                 Semaphore timed wait 0
1  listener                       Active               0
0  Initial                        Sleep                0

番兵というか見張りの人も立ってて、ユーザーが快適に使えるように支えてくれてるのね。 これって、Lispがカーネルのように振る舞ってるんだな。

後は、マニュアルがいつでも見られるように、 ccl-documentation.htmlを転送しとくか。

作ったアプリなりライブラリィーをイメージに焼いて、USBにでも入れておけば、どこでも cclな環境が出来るな。sbclみたいにパソコンにインストールして固定局にしなくても、 どこでも持って行った所で開局出来る移動局、これは有り難い。

まてまて、それって暗黙のうちに里奈が有る事を期待してるね。本当にポータブルするなら ABCLの方がいいんじゃないかい。JAVA電源なら何処にもありそうだからな。

で、移動先は有るんか? 移動はみんなでやるのが楽しい! 引退して田舎に引っ込んじゃった人に出張なんてイベントが巡って くるのか? こなければ、 日本国内で開催のLisp系イベントでも見て、 機会を作ればいいじゃん。

そうそう、出張と言えば、先月都内へ行ってきたよ。糞熱い時期を避けてね。折角行ったんで、 移動に便利な部品を調達しようと思ったんだ。上州屋へ行って電波を釣るための釣竿でも 買おうと思ったんだ。

色々あってわけわかめ。店員さんに相談。グラスファイバーのロッドでなるべく長くて ガイドが付いてないやつで一番安いのを見せて下さい。事前の情報では、1000円近辺で 入手出来るはz。

あんた無線やってるでしょって一発で看破されちゃいましたよ。グラスは重いので釣り人に 嫌われてしまい、メーカーももうカーボンロッドにシフトしちゃったそうな。

それを知らない無線家が月に2-3人は訪れるとか。ロングテールだけどちゃんと需要あるじゃん。 なけなしのやつを見せてもらったら、最長のやつでも2.5mでした。話にならんわ。

某アンテナメーカーは、10Mとかいう長尺のやつを3万円とかで売ってるとか。いきなり 資金難ですな。ポータブルはCLに留めておいた方が無難そうです。

WM3500R用1コインパラボラアンテナでWiMAXスピードアップ なんてのを見ると、高い方も面白そうだなあ。昔は、中華鍋パラボラで、1.2Gをやった ものだよ。今年も富士山山頂に鍋が設置されるのだろうか?