Common Lispで最速のfizzbuzzを実装した話

Kazuho氏のblogにこういうのがあったのでCommon Lispでやってみた。

blog.kazuhooku.com

Common Lispで実装する。

(defmacro fizzbuzz (n)
  (format nil "~{~a ~}" (loop for i from 1 below n
                              collect (cond
                                        ((= 0 (mod i 15)) "fizzbuzz")
                                        ((= 0 (mod i 5)) "buzz")
                                        ((= 0 (mod i 3)) "fizz")
                                        (t i)))))

(defun main ()
  (print (fizzbuzz 100)))

SBCL 1.4.1でディスアセンブルする。

* (disassemble #'main)

; disassembly for MAIN
; Size: 33 bytes. Origin: #x100195397C
; 7C:       498B4C2460       MOV RCX, [R12+96]                ; no-arg-parsing entry point
                                                              ; thread.binding-stack-pointer
; 81:       48894DF8         MOV [RBP-8], RCX
; 85:       488B15A4FFFFFF   MOV RDX, [RIP-92]                ; "1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz "
; 8C:       B902000000       MOV ECX, 2
; 91:       FF7508           PUSH QWORD PTR [RBP+8]
; 94:       B8D8213620       MOV EAX, #x203621D8              ; #<FDEFN PRINT>
; 99:       FFE0             JMP RAX
; 9B:       CC10             BREAK 16                         ; Invalid argument count trap
NIL

文字列をprintするだけのmain関数が生成された。

Pythonのmultiprocessingおよびpipe実行時間

Pythonのmultiprocessingおよびpipeの実行時間計測。

multiprocessing

code

#!/usr/bin/env python
#
# see also : http://docs.python.jp/2.7/library/multiprocessing.html

from sys import stdout
from time import time
from multiprocessing import Process, Pipe

NUMBER = 1000

def measurement(f):
    time_start = time()
    for n in range(NUMBER):
        f()
    time_end = time()
    return time_end - time_start

def dummy():
    pass

def create_process():
    Process()

def start_process():
    Process().start()

def create_pipe():
    Pipe()

def join_process():
    process = Process()
    process.start()
    process.join()

def null_process(pipe1, number):
    for n in range(number):
        pipe1.recv()

def measurement_simplex_pipe():
    time_start = time()
    pipe0, pipe1 = Pipe()
    process = Process(target=null_process, args=(pipe1, NUMBER))
    process.start()
    for n in range(NUMBER):
        pipe0.send(n)
    process.join()
    time_end = time()
    return time_end - time_start

def echo_process(pipe1, number):
    for n in range(number):
        pipe1.send(pipe1.recv())

def measurement_duplex_pipe():
    time_start = time()
    pipe0, pipe1 = Pipe()
    process = Process(target=echo_process, args=(pipe1, NUMBER))
    process.start()
    for n in range(NUMBER):
        pipe0.send(n)
        pipe0.recv()
    process.join()
    time_end = time()
    return time_end - time_start

stdout.write("pass, %f\n" % measurement(dummy))
stdout.write("create process, %f\n" % measurement(create_process))
stdout.write("start process, %f\n" % measurement(start_process))
stdout.write("join process, %f\n" % measurement(join_process))
stdout.write("create pipe, %f\n" % measurement(create_pipe))
stdout.write("simplex pipe, %f\n" % measurement_simplex_pipe())
stdout.write("duplex pipe, %f\n" % measurement_duplex_pipe())

Python 2.7

処理 実行時間 (ms)
pass 0.000079
create process 0.003357
start process 0.245117
join process 0.976598
create pipe 0.011329
simplex pipe 0.003099
duplex pipe 0.011246

Python 3.5

処理 実行時間 (ms)
pass 0.000067
create process 0.003868
start process 0.415079
join process 1.492507
create pipe 0.035219
simplex pipe 0.007089
duplex pipe 0.047015

pipe

code

#!/usr/bin/env python
#
# see also : http://docs.python.jp/2.7/library/multiprocessing.html
#            http://docs.chainer.org/en/stable/tutorial/basic.html

from sys import stdout
from time import time
from multiprocessing import Process, Pipe
from chainer import Chain, ChainList
from chainer.links import Linear

NUMBER = 1000

def measurement(f):
    time_start = time()
    for n in range(NUMBER):
        f()
    time_end = time()
    return time_end - time_start

def null_process(pipe1, number):
    for n in range(number):
        pipe1.recv()

def measurement_simplex_pipe(klass):
    time_start = time()
    pipe0, pipe1 = Pipe()
    process = Process(target=null_process, args=(pipe1, NUMBER))
    process.start()
    for n in range(NUMBER):
        pipe0.send(klass)
    process.join()
    time_end = time()
    return time_end - time_start

def echo_process(pipe1, number):
    for n in range(number):
        pipe1.send(pipe1.recv())

def measurement_duplex_pipe(klass):
    time_start = time()
    pipe0, pipe1 = Pipe()
    process = Process(target=echo_process, args=(pipe1, NUMBER))
    process.start()
    for n in range(NUMBER):
        pipe0.send(klass)
        pipe0.recv()
    process.join()
    time_end = time()
    return time_end - time_start

class MyChain(Chain):
    def __init__(self):
        super(MyChain, self).__init__(
            l1=Linear(784, 100),
            l2=Linear(100, 100),
            l3=Linear(100, 10)
        )

    def __call__(self, x):
        h1 = relu(self.l1(x))
        h2 = relu(self.l2(h1))
        return self.l3(h2)

class MyChainList(ChainList):
    def __init__(self):
        super(MyChainList, self).__init__(
            Linear(784, 100),
            Linear(100, 100),
            Linear(100, 10)
        )

    def __call__(self, x):
        h1 = relu(self[0](x))
        h2 = relu(self[1](h1))
        return self.l3(h2)

classies = [Chain, ChainList, MyChain, MyChainList]

for k in classies:
    stdout.write("create instance %s, %f\n" % (k, measurement(lambda: k())))

for k in classies:
    stdout.write("simplex pipe %s, %f\n" % (k, measurement_simplex_pipe(k)))

for k in classies:
    stdout.write("duplex pipe %s, %f\n" % (k, measurement_duplex_pipe(k)))

Python 2.7

処理 実行時間 (ms)
create instance Chain 0.003006
create instance ChainList 0.001593
create instance MyChain 3.788916
create instance MyChainList 3.780761
simplex pipe Chain 0.005608
simplex pipe ChainList 0.005627
simplex pipe MyChain 0.006494
simplex pipe MyChainList 0.006871
duplex pipe Chain 0.029776
duplex pipe ChainList 0.034982
duplex pipe MyChain 0.033020
duplex pipe MyChainList 0.035376

Python 3.5

処理 実行時間 (ms)
create instance Chain 0.002134
create instance ChainList 0.001779
create instance MyChain 4.150180
create instance MyChainList 4.152344
simplex pipe Chain 0.013076
simplex pipe ChainList 0.013038
simplex pipe MyChain 0.013047
simplex pipe MyChainList 0.010454
duplex pipe Chain 0.065646
duplex pipe ChainList 0.070427
duplex pipe MyChain 0.076342
duplex pipe MyChainList 0.079283

ZenBook3のベンチマーク

SysBenchを使ってZenBook3のベンチマークを取ってみた。

インストール

apt install sysbench

ファイルIO

準備する。

cd /tmp
sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw prepare
sysbench 0.4.12:  multi-threaded system evaluation benchmark

128 files, 24576Kb each, 3072Mb total
Creating files for the test...

ランダム読み書き

helpにあったとおりにベンチマークを実行する。

sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 16

Extra file open flags: 0
128 files, 24Mb each
3Gb total file size
Block size 16Kb
Number of random requests for random IO: 10000
Read/Write ratio for combined random IO test: 1.50
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random r/w test
Threads started!
Done.

Operations performed:  6013 Read, 4009 Write, 12805 Other = 22827 Total
Read 93.953Mb  Written 62.641Mb  Total transferred 156.59Mb  (16.71Mb/sec)
 1069.46 Requests/sec executed

Test execution summary:
    total time:                          9.3711s
    total number of events:              10022
    total time taken by event execution: 0.0953
    per-request statistics:
         min:                                  0.00ms
         avg:                                  0.01ms
         max:                                  5.05ms
         approx.  95 percentile:               0.01ms

Threads fairness:
    events (avg/stddev):           626.3750/185.14
    execution time (avg/stddev):   0.0060/0.00

全然読み方がわからないけど、これ3GB指定してるけど3GBアクセスしてない?なんか読み書きのサイズ調整が必要なのか? とりあえずスレッド数を変更してたら数字が良かったのが8192。

sysbench --num-threads=8192 --test=fileio --file-total-size=3G --file-test-mode=rndrw run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 8192

Extra file open flags: 0
128 files, 24Mb each
3Gb total file size
Block size 16Kb
Number of random requests for random IO: 10000
Read/Write ratio for combined random IO test: 1.50
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random r/w test
Threads started!
Done.

Operations performed:  4091 Read, 6009 Write, 11916 Other = 22016 Total
Read 63.922Mb  Written 93.891Mb  Total transferred 157.81Mb  (448.62Mb/sec)
28711.73 Requests/sec executed

Test execution summary:
    total time:                          0.3518s
    total number of events:              10100
    total time taken by event execution: 275.5066
    per-request statistics:
         min:                                  0.00ms
         avg:                                 27.28ms
         max:                                148.04ms
         approx.  95 percentile:             134.86ms

Threads fairness:
    events (avg/stddev):           1.2329/4.82
    execution time (avg/stddev):   0.0336/0.04

56MB/sくらい。 本当に8192スレッドで実行してるんだろうか。

シーケンシャル読み

sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=seqrd run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 16

Extra file open flags: 0
128 files, 24Mb each
3Gb total file size
Block size 16Kb
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing sequential read test
Threads started!
FATAL: Too large position discovered in request!
Done.

Operations performed:  196607 Read, 0 Write, 0 Other = 196607 Total
Read 3Gb  Written 0b  Total transferred 3Gb  (16.015Gb/sec)
1049527.74 Requests/sec executed

Test execution summary:
    total time:                          0.1873s
    total number of events:              196607
    total time taken by event execution: 2.5037
    per-request statistics:
         min:                                  0.00ms
         avg:                                  0.01ms
         max:                                 41.00ms
         approx.  95 percentile:               0.00ms

Threads fairness:
    events (avg/stddev):           12287.9375/3411.79
    execution time (avg/stddev):   0.1565/0.04

2GB/sくらい。 仕様上PCIe 3.0 x4接続でバスの片道理論性能が4GB/sだから、実効性能限界出てるかはわからないけどそれなりのオーダで計れてそうなのは分かった。

シーケンシャル書き

sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=seqwr run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 16

Extra file open flags: 0
128 files, 24Mb each
3Gb total file size
Block size 16Kb
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing sequential write (creation) test
Threads started!
Done.

Operations performed:  0 Read, 196608 Write, 128 Other = 196736 Total
Read 0b  Written 3Gb  Total transferred 3Gb  (581.51Mb/sec)
37216.69 Requests/sec executed

Test execution summary:
    total time:                          5.2828s
    total number of events:              196608
    total time taken by event execution: 25.3832
    per-request statistics:
         min:                                  0.00ms
         avg:                                  0.13ms
         max:                                 48.05ms
         approx.  95 percentile:               0.03ms

Threads fairness:
    events (avg/stddev):           12288.0000/1694.04
    execution time (avg/stddev):   1.5864/0.01

73MB/sくらい。

片付け

sysbench --num-threads=16 --test=fileio --file-total-size=3G --file-test-mode=rndrw cleanup

結論

これ真面目に色々やらないと正しい値が取れないな。。。

Ubuntu 16.04でdockerを使う

Circle CIとかで色々やりたいので、今更Ubuntu 16.04にdocker入れる。 まずは Install Docker on Ubuntu - Docker にある通りにインストールしてhello world

  • apt install docker.io
  • service docker start
  • usermod -aG docker $USER
  • ログアウトしてログイン
  • docker run hello-world

こんなのが出れば成功。

Hello from Docker!

まずは、もなにもこれで終わりか。

Raspberry PiのBluetoothをCommon Lispから使えなかった

rp3bのbluetoothcommon lispから使いたい。 bluezのラッパーから使うだけだけどc2ffiを実行できるのか?

とりあえずhu.dwim.bluezをロード

ros use sbcl-bin
ros run
(ql:quickload :hu.dwim.bluez)
; caught ERROR:
;   READ error during COMPILE-FILE: unmatched close parenthesisLine: 82, Column: 19, File-Position: 2874Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/toolchain/c-toolchain.lisp" {520B3241}>
While evaluating the form starting at line 30, column 0
  of #P"/home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd":

debugger invoked on a LOAD-SYSTEM-DEFINITION-ERROR: Error while trying to load definition for system cffi-libffi from pathname /home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd: COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "cffi-toolchain" "toolchain" "c-toolchain">

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY                        ] Retry compiling #<CL-SOURCE-FILE "cffi-toolchain" "toolchain" "c-toolchain">.
  1: [ACCEPT                       ] Continue, treating compiling #<CL-SOURCE-FILE "cffi-toolchain" "toolchain" "c-toolchain"> as having been successful.
  2: [RETRY                        ] Retry EVAL of current toplevel form.
  3: [CONTINUE                     ] Ignore error and continue loading file "/home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd".
  4: [ABORT                        ] Abort loading file "/home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd".
  5:                                 Retry ASDF operation.
  6: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
  7:                                 Give up on "hu.dwim.bluez"
  8:                                 Exit debugger, returning to top level.

((FLET #:H0 :IN LOAD-ASD) #<COMPILE-FILE-ERROR {5219A129}>)
0] 

閉じ括弧が合わないコンパイルエラーになるぞ。どういうことだ。。。

c2ffiのインストール

GitHub - rpav/c2ffi: Clang-based FFI wrapper generatorをビルドしたいのでllvmとかをインストール。

sudo apt-get install clang llvm libtool-bin libclang-dev

masterのreadme見ると3.5はサポートされてないがどうするか。 と、おもったらllvm-3.5のブランチもあった。

git clone https://github.com/rpav/c2ffi
cd c2ffi
git checkout llvm-3.5
./autogen
mkdir build
cd build
../configure
make
./src/c2ffi -h
make install

hu.dwim.bluezの修正を試みる

とりあえずソースコードをもらってくる。

git clone https://github.com/attila-lendvai/hu.dwim.bluez
cd .roswell/local-projects/
ln -s ~/hu.dwim.bluez/
cd
ros run
(ql:quickload :hu.dwim.bluez)
To load "hu.dwim.bluez":
  Load 1 ASDF system:
    hu.dwim.bluez
; Loading "hu.dwim.bluez"
; 
; caught ERROR:
;   READ error during COMPILE-FILE: unmatched close parenthesisLine: 82, Column: 19, File-Position: 2874Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/toolchain/c-toolchain.lisp" {516C5241}>
While evaluating the form starting at line 30, column 0
  of #P"/home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd":

debugger invoked on a LOAD-SYSTEM-DEFINITION-ERROR: Error while trying to load definition for system cffi-libffi from pathname /home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd: COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "cffi-toolchain" "toolchain" "c-toolchain">

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY                        ] Retry compiling #<CL-SOURCE-FILE "cffi-toolchain" "toolchain" "c-toolchain">.
  1: [ACCEPT                       ] Continue, treating compiling #<CL-SOURCE-FILE "cffi-toolchain" "toolchain" "c-toolchain"> as having been successful.
  2: [RETRY                        ] Retry EVAL of current toplevel form.
  3: [CONTINUE                     ] Ignore error and continue loading file "/home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd".
  4: [ABORT                        ] Abort loading file "/home/pi/.roswell/lisp/quicklisp/dists/quicklisp/software/cffi_0.17.1/cffi-libffi.asd".
  5:                                 Retry ASDF operation.
  6: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
  7:                                 Give up on "hu.dwim.bluez"
  8:                                 Exit debugger, returning to top level.

((FLET #:H0 :IN LOAD-ASD) #<COMPILE-FILE-ERROR {517AB901}>)
0] 

よく見たらcffiか。。。

githubからcffiをもらってくる

git clone https://github.com/cffi/cffi
cd ~/.roswell/local-projects
ln -s ~/cffi
cd
ros run
(ql:quickload :hu.dwim.bluez)
To load "hu.dwim.bluez":
  Load 1 ASDF system:
    hu.dwim.bluez
; Loading "hu.dwim.bluez"
; pkg-config libffi --cflags

.; cc -marm -o /home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel-tmp7LQ0A0VI -I/home/pi/cffi/ /home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel.c
/home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel.c: In function ‘main’:
/home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel.c:82:41: error: ‘FFI_UNIX64’ undeclared (first use in this function)
   fprintf(output, "%"PRIiMAX, (intmax_t)FFI_UNIX64);
                                         ^
/home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel.c:82:41: note: each undeclared identifier is reported only once for each function it appears in

debugger invoked on a CFFI-GROVEL:GROVEL-ERROR: Subprocess #<UIOP/RUN-PROGRAM::PROCESS-INFO {524CBF21}>
 with command ("cc" "-marm" "-o" "/home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel-tmp7LQ0A0VI" "-I/home/pi/cffi/" "/home/pi/.cache/common-lisp/sbcl-1.3.9-linux-arm/sbcl-bin-1.3.9/home/pi/cffi/libffi/libffi-types__grovel.c")
 exited with error code 1

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY                        ] Retry PROCESS-OP on #<GROVEL-FILE "cffi-libffi" "libffi" "libffi-types">.
  1: [ACCEPT                       ] Continue, treating PROCESS-OP on #<GROVEL-FILE "cffi-libffi" "libffi" "libffi-types"> as having been successful.
  2:                                 Retry ASDF operation.
  3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
  4: [ABORT                        ] Give up on "hu.dwim.bluez"
  5:                                 Exit debugger, returning to top level.

(CFFI-GROVEL:GROVEL-ERROR "~a" #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {524CC061}>)
0] 

FFI_UNIX64 はなんか32ビットarmのlibffiにはないっぽい。

diff --git a/libffi/libffi-types.lisp b/libffi/libffi-types.lisp
index 939a87b..1b47c98 100644
--- a/libffi/libffi-types.lisp
+++ b/libffi/libffi-types.lisp
@@ -69,6 +69,7 @@
 (cenum abi
  ((:default-abi "FFI_DEFAULT_ABI"))
  ((:sysv "FFI_SYSV"))
+ #-arm
  ((:unix64 "FFI_UNIX64")))
 
 (ctype ffi-abi "ffi_abi")

修正してもう一度 hu.dwim.bleuz をロード。

(ql:quickload :hu.dwim.bluez)
; Loading "hu.dwim.bluez"
; CFFI/C2FFI is generating the file #P"/home/pi/hu.dwim.bluez/c2ffi-spec/bluez.arm-pc-linux-gnu.lisp"
........
debugger invoked on a COMMON-LISP:SIMPLE-ERROR: Key :STORAGE-CLASS not found in json entry ((:TAG . "function") (:NAME . "close") (:LOCATION . "/usr/include/unistd.h:353:12") (:VARIADIC) (:INLINE) (:STORAGE--CLASS . "extern") (:PARAMETERS ((:TAG . "parameter") (:NAME . "__fd") (:TYPE (:TAG . ":int")))) (:RETURN-TYPE (:TAG . ":int"))).

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY                        ] Retry GENERATE-LISP-OP on #<C2FFI-FILE "hu.dwim.bluez" "c2ffi-spec" "bluez.h">.
  1: [ACCEPT                       ] Continue, treating GENERATE-LISP-OP on #<C2FFI-FILE "hu.dwim.bluez" "c2ffi-spec" "bluez.h"> as having been successful.
  2:                                 Retry ASDF operation.
  3: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
  4: [ABORT                        ] Give up on "hu.dwim.bluez"
  5:                                 Exit debugger, returning to top level.

(CFFI/C2FFI::JSON-VALUE #<unavailable argument> #<unavailable argument> :OTHERWISE COMMON-LISP:NIL)
0] 

:STORAGE-CLASS not found?

なかなか上手く行かない。。。

Raspberry PiでCommon Lispの起動が遅い

Raspberry Pi 3 Model B買ってCommon Lisp入れた - gos-k’s blog でちょっと触っていて起動が遅い気がするのでバージョン確認出来たものについてとりあえず時間計測する。

ros use sbcl-bin
time ros run -e "(quit)"
real   0m26.860s
user    0m24.720s
sys 0m0.480s
ros use ccl-bin
time ros run -e "(quit)"
real 0m8.136s
user    0m7.890s
sys 0m0.170s
ros use ecl
time ros run -e "(quit)"
real   0m7.412s
user    0m7.050s
sys 0m0.100s

sbclが極端に遅い?

pc側で何となくstraceして、何となくwcしてみる。

strace -o sbcl-strace-quit.txt ros run -L sbcl-bin -e "(quit)"
strace -o ccl-strace-quit.txt ros run -L ccl-bin -e "(quit)"
strace -o ecl-strace-quit.txt ros run -L ecl -e "(quit)"
wc *-strace-quit.txt
   1407    9939  106260 ccl-strace-quit.txt
   6254   38242  632461 ecl-strace-quit.txt
   7705   46700  728444 sbcl-strace-quit.txt

cclが少なめだな。 raspi側で何となくstraceして、何となくwcしてみる。

   1216    7387   82418 ccl-strace-quit.txt
   6867   40908  699180 ecl-strace-quit.txt
  25343  151090 1769082 sbcl-strace-quit.txt

他は数割だけど、sbclの行数が3倍以上違うのなんだろ? プロセッサのアーキテクチャが違うとはいえ、同じosの同じ処理系でこんなに呼び出し回数違うもんなのか?

raspi上でpython, ruby, nodeあたりを起動してみて時間は計ってないけど、体感的にはenterキー押すのと処理系の起動にタイムラグがほぼないので1秒より遥に短いはず。

sbclの結果をざっと眺めると cacheflush を連発してるからこれが遅いのか? あとopenの前にパスの全部にlstat出しまくってるのもこれなんんだろ? まあいずれにしてもCommon Lispは現状処理系選んで起動に8秒か。。。

Raspberry Pi 3 Model B買ってCommon Lisp入れた

Raspberry Pi 3 Model B - Raspberry Pi を購入したのでCommon Lispを動かしてみたメモ。

NOOBSのSDカード作成

PC上で Download NOOBS for Raspberry Pi から NOOBS LITE v1.9をダウンロードし、 NOOBS For Raspberry Pi – Rants & Raves – The Blog! を参考にしてSDカードを作成する。

Raspbianインストール

よく分からないので公式のRaspbianをインストールする。

どこかにありそうな情報を取得

lscpu
Architecture:          armv7l
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             1
Model name:            ARMv7 Processor rev 4 (v7l)
CPU max MHz:           1200.0000
CPU min MHz:           600.0000
uname -a
Linux raspberrypi 4.4.11-v7+ #888 SMP Mon May 23 20:10:33 BST 2016 armv7l GNU/Linux

公式には ARMv8 て書いてあるけど v7 なのか?

Linuxbrewインストール

sudo apt-get install build-essential curl git python-setuptools ruby
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install)"
echo 'Pexport ATH="$HOME/.linuxbrew/bin:$PATH"' >> .profile
. ~/.profile
brew install hello

動かない。。。

==> Downloading https://ftpmirror.gnu.org/hello/hello-2.10.tar.gz
==> Downloading from http://ftp.jaist.ac.jp/pub/GNU/hello/hello-2.10.tar.gz
######################################################################## 100.0%
==> ./configure --disable-silent-rules --prefix=/home/pi/.linuxbrew/Cellar/hello/2.10
*** Error in `/usr/bin/gcc-4.9': double free or corruption (top): 0x01e66718 ***
Last 15 lines from /home/pi/.cache/Homebrew/Logs/hello/01.configure:
--prefix=/home/pi/.linuxbrew/Cellar/hello/2.10

configure: WARNING: unrecognized options: --disable-debug
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for gcc... /usr/bin/gcc-4.9
checking whether the C compiler works... no
configure: error: in `/tmp/hello-20160910-2414-1lq40k3/hello-2.10':
configure: error: C compiler cannot create executables
See `config.log' for more details

READ THIS: https://github.com/Linuxbrew/brew/blob/master/share/doc/homebrew/Troubleshooting.md#troubleshooting
If reporting this issue please do so at (not Homebrew/brew):
  https://github.com/Linuxbrew/homebrew-core/issues

C compiler cannot create executables って何だ? double free or corruption の方か? alternativesを使ってgccを4.8に変えてみたが、linuxbrewの使うgccバージョンが4.9から変更されなかったのでとりあえず諦める。

Roswellインストール

linuxbrewを使わず直接roswellをビルドする。

sudo apt-get install autoconf automake libcurl4-openssl-dev
git clone https://github.com/roswell/roswell.git
cd roswell
./bootstrap
./configure
make
make install
ros init
ros --version
roswell 0.0.6.65(00f7451)

処理系色々インストール

SBCL

ros install sbcl-bin
ros use sbcl-bin
ros run -- --version
SBCL 1.3.9

CCL

ros install ccl-bin
ros use ccl-bin
ros run -- --version
Version 1.11-r16635  (LinuxARM32)

ECL

ros install ecl
ros use ecl
ros run -- --version
ECL 16.1.2

CMUL

ros install cmu-bin
Installing cmu-bin/21a...
Downloading archive:https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2
Downloading https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2
Unhandled UIOP/RUN-PROGRAM:SUBPROCESS-ERROR:
  Subprocess with command "/usr/local/bin/ros roswell-internal-use download https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2 /home/pi/.roswell/archives/cmucl-21a-armhf-linux.tar.bz2"
 exited with error code 2

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {52D82811}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {52A38E91}> #<unavailable argument>)
1: (SB-DEBUG::RUN-HOOK SB-EXT:*INVOKE-DEBUGGER-HOOK* #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {52A38E91}>)
2: (INVOKE-DEBUGGER #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {52A38E91}>)
3: (CERROR "IGNORE-ERROR-STATUS" UIOP/RUN-PROGRAM:SUBPROCESS-ERROR :COMMAND "/usr/local/bin/ros roswell-internal-use download https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2 /home/pi/.roswell/archives/cmucl-21a-armhf-linux.tar.bz2" :CODE 2 :PROCESS NIL)
4: (UIOP/RUN-PROGRAM::%CHECK-RESULT 2 :COMMAND "/usr/local/bin/ros roswell-internal-use download https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2 /home/pi/.roswell/archives/cmucl-21a-armhf-linux.tar.bz2" :PROCESS NIL :IGNORE-ERROR-STATUS NIL)
5: ((LAMBDA (UIOP/RUN-PROGRAM::REDUCED-INPUT #:G7867) :IN UIOP/RUN-PROGRAM::%USE-SYSTEM) :INTERACTIVE #<unavailable argument>)
6: (UIOP/RUN-PROGRAM::%USE-SYSTEM "/usr/local/bin/ros roswell-internal-use download https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2 /home/pi/.roswell/archives/cmucl-21a-armhf-linux.tar.bz2" :INPUT :INTERACTIVE :ERROR-OUTPUT :INTERACTIVE :IF-INPUT-DOES-NOT-EXIST :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-OUTPUT-EXISTS :OVERWRITE :ELEMENT-TYPE :DEFAULT :EXTERNAL-FORMAT :UTF-8 :OUTPUT :INTERACTIVE :ERROR-OUTPUT :INTERACTIVE)
7: (ROS:ROSWELL ("roswell-internal-use" "download" "https://common-lisp.net/project/cmucl/downloads/release/21a/cmucl-21a-armhf-linux.tar.bz2" #P"/home/pi/.roswell/archives/cmucl-21a-armhf-linux.tar.bz2") :INTERACTIVE NIL)
8: (ROS.INSTALL::CMU-BIN-DOWNLOAD (:TARGET "cmu-bin" :VERSION "21a" :ARGV NIL))
9: (INSTALL-IMPL "cmu-bin" NIL NIL)
10: (INSTALL-IMPL-IF-PROBED "cmu-bin" NIL NIL)
11: (MAIN #<unused argument> "cmu-bin")
12: (SB-INT:SIMPLE-EVAL-IN-LEXENV (APPLY (QUOTE MAIN) ROS:*ARGV*) #<NULL-LEXENV>)
13: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ROS:QUIT (APPLY (QUOTE MAIN) ROS:*ARGV*)) #<NULL-LEXENV>)
14: (SB-EXT:EVAL-TLF (ROS:QUIT (APPLY (QUOTE MAIN) ROS:*ARGV*)) NIL NIL)
15: ((LABELS SB-FASL::EVAL-FORM :IN SB-INT:LOAD-AS-SOURCE) (ROS:QUIT (APPLY (QUOTE MAIN) ROS:*ARGV*)) NIL)
16: (SB-INT:LOAD-AS-SOURCE #<CONCATENATED-STREAM :STREAMS NIL {52C0C2A1}> :VERBOSE NIL :PRINT NIL :CONTEXT "loading")
17: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<CONCATENATED-STREAM :STREAMS NIL {52C0C2A1}> NIL)
18: (LOAD #<CONCATENATED-STREAM :STREAMS NIL {52C0C2A1}> :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST T :EXTERNAL-FORMAT :DEFAULT)
19: ((FLET ROS::BODY :IN ROS:SCRIPT) #<SB-SYS:FD-STREAM for "file /usr/local/etc/roswell/install.ros" {52C0C179}>)
20: (ROS:SCRIPT :SCRIPT "/usr/local/etc/roswell/install.ros" "install" "cmu-bin")
21: (ROS:RUN ((:SCRIPT "/usr/local/etc/roswell/install.ros" "install" "cmu-bin") (:QUIT NIL)))
22: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ROS:RUN (QUOTE ((:SCRIPT "/usr/local/etc/roswell/install.ros" "install" "cmu-bin") (:QUIT NIL)))) #<NULL-LEXENV>)
23: (EVAL (ROS:RUN (QUOTE ((:SCRIPT "/usr/local/etc/roswell/install.ros" "install" "cmu-bin") (:QUIT NIL)))))
24: (SB-IMPL::PROCESS-EVAL/LOAD-OPTIONS ((:EVAL . "(progn #-ros.init(cl:load \"/usr/local/etc/roswell/init.lisp\"))") (:EVAL . "(ros:quicklisp)") (:EVAL . "(ros:run '((:script \"/usr/local/etc/roswell/install.ros\"\"install\"\"cmu-bin\")(:quit ())))")))
25: (SB-IMPL::TOPLEVEL-INIT)
26: ((FLET #:WITHOUT-INTERRUPTS-BODY-72 :IN SB-EXT:SAVE-LISP-AND-DIE))
27: ((LABELS SB-IMPL::RESTART-LISP :IN SB-EXT:SAVE-LISP-AND-DIE))

unhandled condition in --disable-debugger mode, quitting

ABCL

ros install abcl-bin
ros use abcl-bin
Invalid maximum heap size: -Xmx4g
The specified size exceeds the maximum representable size.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Error: unable to use 'abcl-bin'

4G固定なのかな?

CLISP

ros install clisp
Installing clisp/2.49...
prefix: #P"/home/pi/.roswell/impls/armhf/linux/clisp/2.49/"
chdir /home/pi/.roswell/src/clisp-2.49/src/
Unhandled UIOP/RUN-PROGRAM:SUBPROCESS-ERROR:
  Subprocess with command "make install"
 exited with error code 2

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {52D85581}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {514A8129}> #<unavailable argument>)
1: (SB-DEBUG::RUN-HOOK SB-EXT:*INVOKE-DEBUGGER-HOOK* #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {514A8129}>)
2: (INVOKE-DEBUGGER #<UIOP/RUN-PROGRAM:SUBPROCESS-ERROR {514A8129}>)
3: (CERROR "IGNORE-ERROR-STATUS" UIOP/RUN-PROGRAM:SUBPROCESS-ERROR :COMMAND "make install" :CODE 2 :PROCESS NIL)
4: (UIOP/RUN-PROGRAM::%CHECK-RESULT 2 :COMMAND "make install" :PROCESS NIL :IGNORE-ERROR-STATUS NIL)
5: ((LAMBDA (UIOP/RUN-PROGRAM::REDUCED-INPUT #:G7867) :IN UIOP/RUN-PROGRAM::%USE-SYSTEM) NIL #<unavailable argument>)
6: ((FLET #:BEFORE7398 :IN UIOP/RUN-PROGRAM::%CALL-WITH-PROGRAM-IO) #P"/tmp/tmpZWLLOVAH.tmp")
7: (UIOP/STREAM:CALL-WITH-TEMPORARY-FILE #<CLOSURE (FLET #:BEFORE7398 :IN UIOP/RUN-PROGRAM::%CALL-WITH-PROGRAM-IO) {72593B95}> :WANT-STREAM-P NIL :WANT-PATHNAME-P T :DIRECTION :IO :KEEP NIL :AFTER NIL :DIRECTORY NIL :TYPE "tmp" :PREFIX NIL :SUFFIX NIL :ELEMENT-TYPE NIL :EXTERNAL-FORMAT NIL)
8: ((LABELS UIOP/RUN-PROGRAM::HARD-CASE :IN UIOP/RUN-PROGRAM::%CALL-WITH-PROGRAM-IO))
9: (UIOP/RUN-PROGRAM::%USE-SYSTEM "make install" :INPUT NIL :ERROR-OUTPUT NIL :IF-INPUT-DOES-NOT-EXIST :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-OUTPUT-EXISTS :OVERWRITE :ELEMENT-TYPE :DEFAULT :EXTERNAL-FORMAT :UTF-8 :OUTPUT T)
10: (ROS.INSTALL::CLISP-INSTALL (:TARGET "clisp" :VERSION "2.49" :ARGV NIL))
11: (INSTALL-IMPL "clisp" NIL NIL)
12: (INSTALL-IMPL-IF-PROBED "clisp" NIL NIL)
13: (MAIN #<unused argument> "clisp")
14: (SB-INT:SIMPLE-EVAL-IN-LEXENV (APPLY (QUOTE MAIN) ROS:*ARGV*) #<NULL-LEXENV>)
15: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ROS:QUIT (APPLY (QUOTE MAIN) ROS:*ARGV*)) #<NULL-LEXENV>)
16: (SB-EXT:EVAL-TLF (ROS:QUIT (APPLY (QUOTE MAIN) ROS:*ARGV*)) NIL NIL)
17: ((LABELS SB-FASL::EVAL-FORM :IN SB-INT:LOAD-AS-SOURCE) (ROS:QUIT (APPLY (QUOTE MAIN) ROS:*ARGV*)) NIL)
18: (SB-INT:LOAD-AS-SOURCE #<CONCATENATED-STREAM :STREAMS NIL {52C0B261}> :VERBOSE NIL :PRINT NIL :CONTEXT "loading")
19: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) #<CONCATENATED-STREAM :STREAMS NIL {52C0B261}> NIL)
20: (LOAD #<CONCATENATED-STREAM :STREAMS NIL {52C0B261}> :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST T :EXTERNAL-FORMAT :DEFAULT)
21: ((FLET ROS::BODY :IN ROS:SCRIPT) #<SB-SYS:FD-STREAM for "file /usr/local/etc/roswell/install.ros" {52C0B139}>)
22: (ROS:SCRIPT :SCRIPT "/usr/local/etc/roswell/install.ros" "install" "clisp")
23: (ROS:RUN ((:SCRIPT "/usr/local/etc/roswell/install.ros" "install" "clisp") (:QUIT NIL)))
24: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ROS:RUN (QUOTE ((:SCRIPT "/usr/local/etc/roswell/install.ros" "install" "clisp") (:QUIT NIL)))) #<NULL-LEXENV>)
25: (EVAL (ROS:RUN (QUOTE ((:SCRIPT "/usr/local/etc/roswell/install.ros" "install" "clisp") (:QUIT NIL)))))
26: (SB-IMPL::PROCESS-EVAL/LOAD-OPTIONS ((:EVAL . "(progn #-ros.init(cl:load \"/usr/local/etc/roswell/init.lisp\"))") (:EVAL . "(ros:quicklisp)") (:EVAL . "(ros:run '((:script \"/usr/local/etc/roswell/install.ros\"\"install\"\"clisp\")(:quit ())))")))
27: (SB-IMPL::TOPLEVEL-INIT)
28: ((FLET #:WITHOUT-INTERRUPTS-BODY-72 :IN SB-EXT:SAVE-LISP-AND-DIE))
29: ((LABELS SB-IMPL::RESTART-LISP :IN SB-EXT:SAVE-LISP-AND-DIE))

unhandled condition in --disable-debugger mode, quitting