arm

スフィロ ボルト

Sphero完全ガイド book

これ面白いな。ボールがプログラミング通りに回転しながら移動する。昔に流 行ったlogoと組合せると、亀さんの代りをさせられる。

どんな原理で動いているのだろう? 直ぐに思い付くのは、重心を移動させて転がすって方法だけど、他にもあるかな?

何やらLEDの表示器が付いていたり、デジタルコンパスやら青葉無線機能が有っ たりと、周辺機器が豊富にぶら下っている。IO制御の塊なのね。こういうロボッ トを制御するCPUはarmな石だろうね。

予定調和的に、ラズパイ・ボードでも採用してるのなか。このロボット欲しい けど、床に絵を書くだけじゃ、つまらない。だったら、アレだな。

Raspberry Pi for poor man

以前に作ったarmな環境が古くなってて、emacsをコンパイルするにに必要な pkgが手に入らなくなってた。ええ、例のbytecode実行系がarmな石だと、どう なるか確認したかったんです。

そこで、下記を参考に、新しい環境を作る事にした。こちらは、容量制限を回避する方法。

Raspberry Pi のセルフビルド環境を QEMU で作る

実験なので、手間のかからない下記の方法を取 る事にした。

Raspberry Pi用バイナリをQEMUエミュレータで動かす方法(ユーザーモードエミュレーション)

起動スクリプト

sakae@usvr:~/sim/arm$ cat boot
#!/bin/bash

sudo mount -o offset=50331648 181113.img rootfs
sudo mount -t sysfs sysfs rootfs/sys
sudo mount -t proc proc rootfs/proc
sudo mount -t devtmpfs udev rootfs/dev
sudo mount -t devpts devpts rootfs/dev/pts

sudo QEMU_CPU=arm11mpcore /usr/sbin/chroot rootfs

sudo umount rootfs/dev/pts
sudo umount rootfs/dev
sudo umount rootfs/proc
sudo umount rootfs/sys
sudo umount /home/sakae/sim/arm/rootfs

とりあえずの、動作確認

sakae@usvr:~/sim/arm$ ./boot
root@usvr:/# su - pi
pi@usvr:~ $ uname -a
Linux usvr 4.15.0-43-generic #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018 armv7l GNU/Linux
pi@usvr:~ $ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/loop3       1712920 1031916    575944  65% /
udev              978036       0    978036   0% /dev
pi@usvr:~ $ exit
exit
root@usvr:/# exit
exit

空容量が575Mあれば、emacsの一式ぐらいコンパイルできるでしょう。(インス トールはしない積りです)

なお、piユーザーに切り替えておかないと、前世代の石になっちゃう様なんで 注意。

make emacs for arm

早速コンパイルしてみる。armを起動させると、rootfsの中にファイルシステ ムが出現するんで、rootfs/tmp あたりに、tar球を落す。ユーザーpiに取って は、空から突然降ってきた隕石みたいなものでしょう。

後は、みみっちい設定でconfigする。

pi@usvr:~/emacs-26.1 $ ./configure --with-sound=no \
 --without-cairo --without-dbus --without-gconf --without-gif \
 --without-gsettings --with-x-toolkit=no --without-jpeg \
 --without-lcms2 \
 --without-m17n-flt --without-imagemagick --without-libotf \
 --without-png \
 --without-toolkit-scroll-bars --without-rsvg  --without-tiff \
 --without-x --without-xim --without-xpm  --without-xwidgets  \
 --with-gnutls=no

大体開発環境は初期状態ではいっているんだけど、特殊なやつは無いから入れ ろとアドバイスされたよ。

checking for library containing tputs... no
configure: error: The required function 'tputs' was not found in any library.
The following libraries were tried (in order):
  libtinfo, libncurses, libterminfo, libcurses, libtermcap
Please try installing whichever of these libraries is most appropriate
for your system, together with its header files.
For example, a libncurses-dev(el) or similar package.

で、コンパイル

  :
make[1]: Nothing to be done for 'info-dir'.
make[1]: Leaving directory '/home/pi/emacs-26.1'

real    14m52.877s
user    14m22.355s
sys     0m31.999s

pi@usvr:~/emacs-26.1 $ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/loop3       1712920 1365644    242216  85% /
udev              978036       0    978036   0% /dev

何とかDISKも足りたようだ。

pi@usvr:~/emacs-26.1/src $ file emacs
emacs: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
dynamically linked,
interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0,
BuildID[sha1]=a97c7cbf8c32e100e72d630332ccc605385d990f, not stripped

こんな具合に完成した。よかったね。

bytecode for arm

          op -= Bvarref;
     274:       e2411008        sub     r1, r1, #8
            Lisp_Object v1 = vectorp[op], v2;
     278:       e51b3040        ldr     r3, [fp, #-64]  ; 0xffffffc0
     27c:       e7933101        ldr     r3, [r3, r1, lsl #2]
            if (!SYMBOLP (v1)
     280:       e3130007        tst     r3, #7
     284:       1a000005        bne     2a0 <exec_byte_code+0x280>
  return lisp_h_XSYMBOL (a);
     288:       e59f2da4        ldr     r2, [pc, #3492] ; 1034 <exec_byte_code+0x1014>
     28c:       e0831002        add     r1, r3, r2
                || XSYMBOL (v1)->u.s.redirect != SYMBOL_PLAINVAL
     290:       e7d32002        ldrb    r2, [r3, r2]
     294:       e202200e        and     r2, r2, #14
     298:       e3520008        cmp     r2, #8
     29c:       0a000082        beq     4ac <exec_byte_code+0x48c>
              v2 = Fsymbol_value (v1);
     2a0:       e1a00003        mov     r0, r3
     2a4:       ebfffffe        bl      0 <Fsymbol_value>
            PUSH (v2);
     2a8:       e51b2028        ldr     r2, [fp, #-40]  ; 0xffffffd8
            NEXT;
     2ac:       e51b303c        ldr     r3, [fp, #-60]  ; 0xffffffc4
     2b0:       e2844001        add     r4, r4, #1
            PUSH (v2);
     2b4:       e5a20004        str     r0, [r2, #4]!
            NEXT;
     2b8:       e5541001        ldrb    r1, [r4, #-1]

run temacs

pi@usvr:~/emacs-26.1/src $ ls -l | grep -- -rwxr
-rwxr-xr-x 3 pi pi 29477828 Jan 25 05:56 bootstrap-emacs
-rwxr-xr-x 3 pi pi 29477828 Jan 25 05:56 emacs
-rwxr-xr-x 3 pi pi 29477828 Jan 25 05:56 emacs-26.1.1
-rwxr-xr-x 1 pi pi 12333480 Jan 25 05:55 temacs

これsrcの中の成果物。ハードリンクで3個出来上がってるのはいいんだけど、 容量の小さいtemacsは何者? 考えていても分らないので、走らせちゃえ。

起動した途端に、statusラインが点線のものが表われ、盛んに*.elをローディ ングしてた。*Messages*には、

Loading replace...done
Loading emacs-lisp/tabulated-list...done
Loading buff-menu...done
Loading emacs-lisp/float-sup...done
Loading vc/vc-hooks...done
Loading vc/ediff-hook...done
Loading uniquify...done
Loading electric...done
Loading emacs-lisp/eldoc...done
Loading cus-start...done
Loading tooltip...done
Loading leim/leim-list.el (source)...done
Finding pointers to doc strings...done
Pure-hashed: 14449 strings, 3846 vectors, 36664 conses, 3726 bytecodes, 164 others
For information about GNU Emacs and the GNU system, type C-h C-a.
Loading loadup.el (source)...done

こんな記録が残っていた。そうか、temacsは裸のlispで、それに肉付けしてか ら、全体をダンプすると、emacsになるんだろう。(これ、sbcl等で、シングル バイナリーを作成する手段に使われていたな)

M-x emacs-versionすると

GNU Emacs 26.1 (build 1, armv7l-unknown-linux-gnueabihf) of 2019-01-25

gdbが使えるかと思って試したら、

(gdb) r
Starting program: /home/pi/emacs-26.1/src/emacs
qemu: Unsupported syscall: 26

あえなくハングした。ウブ側のプロセスを確認。

  1660 pts/1    S      0:00 /bin/bash ./boot
  1677 pts/1    S      0:00 sudo QEMU_CPU=arm11mpcore /usr/sbin/chroot rootfs
  1678 pts/1    Sl     0:00 /usr/bin/qemu-arm-static /bin/bash -i
 15855 pts/1    Sl     0:00 /usr/bin/qemu-arm-static /bin/su - pi
 15858 pts/1    Sl     0:00 /usr/bin/qemu-arm-static /bin/bash
 33605 pts/1    Sl+    0:01 /usr/bin/qemu-arm-static /usr/bin/gdb emacs
 33611 pts/1    Tl     0:00 /usr/bin/qemu-arm-static /home/pi/emacs-26.1/src/ema

33605のプロセスを殺せばいいかと思ってやってみたら、chroot自身が終了し ちゃって、ウブのプロンプトに戻ってしまった。gdbは封印しておかなければ!!

comp

こうして、無事にarmな環境が出来たけど、どれぐらいの性能が出るのか確認 したくなる。そこでベンチマークですよ。

感覚的に、amd64でのemacs作成が2分少々、対してarm32では15分弱なんで、ざっ くり8倍ぐらいの違いが有るかなと予想。

ELISP> (benchmark-run (tarai 12 6 0))
(0.859854004 0 0.0)

これ、ウブなamd64機での結果。

ELISP> (benchmark-run (tarai 12 6 0))
(7.848208675 0 0.0)

今度は、armな石のシュミレータ。予想は的中しましたな。ああ、tarai.elcは、 amd64の方で作ったものを、そのまま利用。armな石は、エンディアンがインテ ル系と違うのかな。だとすれば、石の壁を乗り越えている訳だ。 まるで、一度作れば何処でも動くjavaみたいだな。

emacsって、インストールしなくても、普通に使える様になってるの ね。~/.emacs.dは、勝手に作られていたよ。この中に、init.elを突っ込んで おけば、俺様仕様で動いてくれるだろう。

ふと、armな環境がマルチCPUって事を思い出した。Windows10のタスクマネー ジャーでCPUの働きぶりを見たらどうなるのだろう?

結果は、4CPUが動いていた。ウブは、vmwareで2CPUを割り当てているんだけど、 コア数を意味してるのかな?1コアに2論理プロセッサなんで、モニター上では、 全ての石が動いてると報告されるのか。

ウブ側のemacsでやってみると、cpu2,cpu3の負荷が急上昇してる。つられて、 cpu0,cpu1の負荷も上がるけど、cpu2,3側程では無いという結果。

場合によってバラツクが有るなあ。そもそも、taraiって、手分けして実行す るような代物なのかなあ。副作用が無い関数なんで、手分けしようと思えば、 手分けできるだろうけど。

at debian

32Bitなマシンにもarmな環境を作ってみた。こちらは、容量無制限方式。 ウブな方は、環境が181113.imgの中に閉じ込められた(クロージャ方式)ものだ けど、debianな方は、親のDISKの容量制限に引っ掛かるだけ(無理にこじつけ ると、ダイナミック方式だな)

起動スクリプトは、こんな感じにした。

debian:~$ cat sim/arm/boot
#!/bin/bash

sudo mount -t sysfs sysfs rootfs/sys
sudo mount -t proc proc rootfs/proc
sudo mount -t devtmpfs udev rootfs/dev
sudo mount -t devpts devpts rootfs/dev/pts

sudo /usr/sbin/chroot rootfs /bin/bash

sudo umount rootfs/dev/pts
sudo umount rootfs/dev
sudo umount rootfs/proc
sudo umount rootfs/sys

さて、これで何を試そう。ラズパイもどきのarmな石と言っても、動いてしま えば、インテル系のそれと見分けがつかないからね。今更emacsを入れても悩 が無いしね。そんな事で、ヤバそうな、gaucheを試してみる。最近新らしいの が出たしね。

なにが懸念されるかと言うと、一つは、gc。これひょっとしてインテル系に特 化していないか? もう一つは、扱える数値の範囲問題。果たして予想が的中 するか、やってみる。(吾ながら、動機が不純だなあ)

bignum.c: In function ‘bignum_add_int’:
gauche/priv/arith.h:88:15: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
     (c) = ((r)<(x) || ((r)==(x) && ((y)>0||(c)>0)))? 1 : 0;     \
               ^
bignum.c:616:17: note: in expansion of macro ‘UADD’
                 UADD(br->values[i], c, 0, 0);
                 ^~~~
gauche/priv/arith.h:88:15: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
     (c) = ((r)<(x) || ((r)==(x) && ((y)>0||(c)>0)))? 1 : 0;     \
               ^
bignum.c:620:13: note: in expansion of macro ‘UADD’
             UADD(br->values[i], c, 0, y);

微妙な警告だなあ。shiroさんの頭の中を覗いてみたい衝動。これarmな石に特 有な警告かなあ。コンパイルが成功したら、是非 make checkしておこう。

コンパイルの進行状態は、やっとgcエリアをクリアして、本体にかかって来た。 果てしなく時間がかかるなあ。過去の記憶では、emacsを作るより時間がかかっ たはずだからね。

 :
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/pi/Gauche-0.9.7/examples'
cd src; /usr/bin/make -s static

real    76m37.225s
user    75m12.064s
sys     0m27.900s

やっと終わった。やっぱり時間がかるね。当社比、10倍は遅いですって感じか な。

はて、インストールしなくても、普通に使えたかな?

pi@debian:~/Gauche-0.9.7/src $ ./gosh
*** ERROR: cannot find "gauche/interactive" in ("/usr/local/share/gauche-0.97/site/lib" "/usr/local/share/gauche-0.97/0.9.7/lib")
Stack Trace:
_______________________________________
WARNING: Encountered an error during loading gauche.interactive.  Falling back to basic REPL.
gosh> (cons 1 2)
(1 . 2)
gosh> (define (d n) (* n n))
d
gosh> (d 1111111111111111111111111111111111111111)
1234567901234567901234567901234567901234320987654320987654320987654320987654321

replの便利な機能は、使えないけど、取りあえず動くな。

make[1]: Leaving directory '/home/pi/Gauche-0.9.7/src'
Total: 19601 tests, 19601 passed,     0 failed,     0 aborted.
make[1]: Entering directory '/home/pi/Gauche-0.9.7/src'
make[1]: Leaving directory '/home/pi/Gauche-0.9.7/src'

real    19m38.386s
user    17m58.348s
sys     0m13.920s

暇にまかせてcheckしてみた。問題なしって事で安心しましたよ。と、言いつ つ、普通に使う分には、x86だろうとarmだろうと違いは無し。只の自己満足以 外の何物でも有りません。

Goroutine

上で並行処理の話が出てきた。並行と言えばgolangだなと、馬鹿の一つ覚えで、 goroutineが頭に浮かんだ。例のtaraiで試してみようと、go taraiを複数記述 したけど、実行時間は、0秒。これはおかしいってんで、調べてみたら、待合 せには、特殊な方法が必要と、下記のURLに載ってた。

Go の並行処理

golang の sync パッケージの使い方

そんな訳で、下記を作りあげてみた。

package main

import "fmt"
import "sync"
import "time"

func tarai(x, y, z int) int {
        if x <= y {
                return y
        } else {
                return tarai(tarai(x-1, y, z),
                        tarai(y-1, z, x),
                        tarai(z-1, x, y))
        }
}

func main() {
        start := time.Now()

        var wg sync.WaitGroup
        for i := 0; i < 4; i++ {
                wg.Add(1)
                go func(i int) {
                        fmt.Printf("%d\n", i)
                        tarai(14, 7, 0)
                        wg.Done()
                }(i)
        }
        wg.Wait()

        ex := time.Since(start)
        fmt.Printf("%f\n", ex.Seconds())
}

ちょっと効果の程をvbox上のFreeBSDで確認していみる。CPU数は、2つの環境だ。

make -k
go run tarai.go
0
3.515730

一つの盥だと、3.5秒と出た。四つの盥をリレーさせると、4倍の時間がかかる はずだけど、上の仕掛けで、並列に走るはず。

make -k
go run tarai.go
3
0
1
2
7.125511

短かい時間で盥競争は終了した。負荷をうんと重くして競争を始め、タスクト レーで、CPUの利用率を確認すると58%になってた。CPUパワーが全開 になっていないのね。

Windows10に入れているgoでやってみる。

sakae@atom:/mnt/c/Users/sakae/go/src/tarai$ make
go.exe run tarai.go
0
1.860035
sakae@atom:/mnt/c/Users/sakae/go/src/tarai$ make
go.exe run tarai.go
2
1
3
0
3.310808

随分速いな。負荷をかけると、CPU利用率が100%まであがった。全力疾走なら ぬ、全力漕ぎなんですな。

物はついでなんで、チープな石のセレロン版i386でやってみる。

debian:tarai$ make
go run tarai.go
0
4.670436
debian:tarai$ make
go run tarai.go
3
0
1
2
18.620675

どう頑張ってもCPUは一つなんで、順番に実行するから、4倍の時間がかかるん だな。

taraiはニッチな業界であるLisp国の競技だったけど、これで国際舞台へデビュー だな。来るオリンピックでは、エキシビジョンで、盥漕ぎ競争が行なわれるに 違いない。勿論、バックグランドミュージックと言うか、お囃子は、佐渡おけ さで決まりかな。

まてまて、youは何しに日本へ、って番組で、たらい漕ぎ競争が取り上げられ ていた記憶があるぞ。ちょいと調べてみる。

増田名物 たらいこぎ競争が開催されます

横手市の増田って所が有名なのね。知りませんでした。