Ubuntu 12.04 on beagleboard-xm Rev.C でErlang動いた
Ubuntu 12.04インストール
正月にAndroid動かしてからほったらしになってたbeagleboard-xmですが、ふと思い立ってubuntu入れてみました。
beagleboard-xmへのubuntuのインストールは至って簡単。
ここを参考にさせていただいたらなにもつまづかずにできました。
$ wget http://cdimage.ubuntu.com/releases/12.04/release/ubuntu-12.04-preinstalled-desktop-armhf+omap.img.gz $ gunzip ubuntu-12.04-preinstalled-desktop-armhf+omap.img.gz
SDカードを挿入してsyslogでデバイスを確認。sdcでした.
ddコマンドでイメージファイルをSDカードにコピー。
$ sudo dd bs=4M if=ubuntu-12.04-preinstalled-desktop-armhf+omap.img of=/dev/sdc
以上w あとはこのSDカードをbeagleboard-xmに差して起動。初回はシステム設定ですが、起動までに結構時間がかかります。
さすがにunityだと重くてもっさり加減が我慢できなかったので、以前開発マシンで使っていたWindowMakerを入れることにしました。
$ sudo apt-get install wmaker wmaker-data menu
一旦ログアウトして、ログイン時にWindowMakerを選択すればWindowMakerが起動します。
で、上の写真みたいな感じに。
unityではものすごくモッサリしてましたが、WindowMakerに変えたらサクサク動きます。
あと全体的にSDカードの読み書きがボトルネックになっている感は否めません。最初立ち上がりが遅いと思ってましたが、原因はCPUよりSDカードからの読み込みにありそうです。
なのでSDカードはケチらずに速いやつを買うことをお勧めします。
Erlang RB15B02のインストール
このままじゃなんなんで、Erlang入れてみました。Erlangてサーバーのイメージ強いですけど、てか実際その方面での使用がほとんどでしょうけど、実は組み込みに有利な特性ももってるようです。
いわゆるソフトリアルタイム性ですが、Erlangは各プロセスごとにGCを持ってるそうなので、GCが走ったために全体がグッと止まるということがないようです。試してませんがw
あと、そのプロセスごとのGCはプロセスが破棄されるときに、そのプロセスが確保していた領域を開放するそうなので、メモリをたくさん使う処理は、それ用にプロセス作ってそこで処理をして、そのプロセスを破棄すればGCなのに任意のタイミングでのメモリ解放ができてかつ、それが他のプロセスに、ソフトリアルタイムのレベルでは影響しないとかなんとか。
で、入れてみるわけですが、普通に入りました。
aptであったのですが、なんかそれだと面白くないのでソースから入れてみました。
以前落としてたotp_src_R15B02をbeagleboard上にscpして
$ tar xvzf otp_src_R15B02.tar.gz $ cd otp_src_R15B02/ $ sudo apt-get install libncurses5 libncurses5-dev g++ libssl-dev libcrypto++-dev $ ./configure --enable-threads --enable-kernel-poll --disable-hipe --without-javac --with-ssl --prefix=/usr/local/erlang/R15B02 $ make $ sudo make install $ sudo ln -s /usr/local/erlang/R15B02/bin/* /usr/local/bin/
さすがにコンパイルには時間かかったので、ほっといて寝てましたが、翌朝見たら無事完了してました。
試しに自分が書いたコード落としてみても問題なくコンパイル、動作しました。
あとはこんなの書いてプロセスがたくさん起動してみたりとか
process_test.erl
-module(process_test). -export([go/1]). %% 実行開始 go(Count) -> %% 引数で渡された数のプロセスを新たに生成する Fun = fun(_) -> spawn_link(fun() -> recv() end) end, PidList = lists:map(Fun, lists:seq(1, Count)), %% 全てのプロセスにメッセージを送信 send_messages(PidList), io:format("message sent to ~p processes.~n", [Count]), %% 全てのプロセスからの応答メッセージを受信 recv_messages(Count), io:format("all message returned, ok.~n"). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 基底パターン。全てのプロセスにメッセージ送信完了 send_messages([]) -> ok; %% 再帰しながら各プロセスにメッセージを送信 send_messages([Pid | TailPid]) -> Pid ! {hello, self()}, send_messages(TailPid). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 基底パターン。全てのプロセスから応答メッセージを受信完了 recv_messages(0) -> ok; %% 再帰しながら各プロセスからの応答メッセージを受信 recv_messages(Count) -> receive {ok, _Pid} -> ok end, recv_messages(Count - 1). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% 生成されたプロセス側で実行されるメッセージ受信待機関数 recv() -> receive {hello, From} -> From ! {ok, self()} end.
実行結果葉こんな感じ。
shin@beagle-ubuntu:~/src/process_test$ erl Erlang R15B02 (erts-5.9.2) [source] [async-threads:0] [kernel-poll:false] Eshell V5.9.2 (abort with ^G) 1> c(process_test). {ok,process_test} 2> 2> timer:tc(process_test, go, [1000]). message sent to 1000 processes. all message returned, ok. {88348,ok} 3> 3> 3> timer:tc(process_test, go, [10000]). message sent to 10000 processes. all message returned, ok. {966369,ok} 4> 4> 4> timer:tc(process_test, go, [30000]). message sent to 30000 processes. all message returned, ok. {1426422,ok}
時間の単位はマイクロセカンドなんで、1万プロセス立ち上げて全てのプロセスにメッセージ送って返ってくるまで約0.9秒。30000プロセスなら1.4秒。
同じことをMacBookPro With Ubuntu だと
Erlang R15B02 (erts-5.9.2) [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false] Eshell V5.9.2 (abort with ^G) 1> c(process_test). {ok,process_test} 2> 2> timer:tc(process_test, go, [1000]). message sent to 1000 processes. all message returned, ok. {8334,ok} 3> 3> 3> timer:tc(process_test, go, [10000]). message sent to 10000 processes. all message returned, ok. {74601,ok} 4> 4> 4> timer:tc(process_test, go, [30000]). message sent to 30000 processes. all message returned, ok. {225231,ok}
さすがに差があります。クロック数だけでなくコア数の差も効いているのでしょうか。
それでもあれだけの数のプロセスが比較的短い時間で立ち上がるのが確認できました。
もう眠いので今日はここまで。