2013年5月3日金曜日

ART-Linuxの実験 インストール(その2)

ここからが本番のリアルタイム制御専用システム(AP)のインストールです。急に難易度があがります。(産総研のHPにあった論文(?)をベースにやったことを意味を追加してメモしていきます)

4.必要なパッケージのDL
以下のパッケージをDLしてきます。


ap-linux-image-2.6.32-art-generic_20130227_i386.deb
ap-linux-headers-2.6.32-art-generic_20130227_i386.deb
apboot-1.0_20121213_i386.deb


ap-linux-*は、AP用のkernelです。あと、apbootはそれを起動するためのbootコマンドです。
まず、bootコマンドをインストールします。

sudo dpkg -i apboot-1.0_20121213_i386.deb


5.AP用システムの作成
次にAP用のFS(ファイルシステム)を作ります。これまで知らなかったんですが、Linuxでは試験用に別の形態のシステムを作成して動かす機能があり、それを使ってます。


mkdir -p ${APROOT}
sudo debootstrap ${SUIT} ${APROOT}


${APROOT}はAP用のファイルシステムのパス名で、動作させるコア数分だけ作成するようです。今回はCore2DuoなのでAPは1個しか作れませんから、1個だけです。
次の、debootstrapというコマンドが、当該パスの下に${SUIT}で指示されたUbuntuのファイルシステムを作成します。今回は’lucid’です。デフォルトではこのdebootstrapコマンドは入っていませんから、apt-getなりaptitudeでインストールしましょう。このコマンドはファイルシステムをネットからDLしてくるので、結構時間がかかります。


6.エクスポートの設定
システムを動かすうえで、BSPとAPのファイルシステムを相互に参照できると便利だろうということで、APのファイルシステムをBSP側で公開(export)する設定をします。


echo ${APIP} ${APNAME} >> /etc/hosts
echo ${APROOT} ${APNAME}\(rw,no_root_squash,subtree_check\) >> /etc/exports
exportfs -a


${APIP}はAP用のIPアドレス、${APNAME}はAPのホスト名です。適当に設定しましょう。(もちろんBSPから届くネットワークリーチャブルでなければ意味はないでしょうが)→APNAME=AP0とすること!11項のapbootでAPをAP0として起動しているため、これと合わせておく必要があります!
ちょっと思ったのが、いちいちechoコマンドで設定ファイルを修正していますが、直接viでやった方がいいと思います。一瞬、何をしているのか考え込んでしまいました。


7.ルータの設定
APから外部ネットワークに接続するためにはBSP経由行う必要があります。BSPにルータの設定をしてやらないといけません。/etc/network/interfacesに以下の設定をしてやります。


iface ap0 inet static
address ${BSPIP}
netmask 255.255.255.255
pointopoint ${APIP}
up iptables -t nat -A POSTROUTING -s ${APIP} -o ${ETH} -j MASQUERADE
down iptables -t nat -D POSTROUTING -s ${APIP} -o ${ETH} -j MASQUERADE

BSPにデバイスap0を定義し、これがAPと通信できるようルートを設定しています。${ETH}はBSP側のEthernetデバイスで、通常はeth0でしょう。あと、/etc/sysctl.confで以下の行のコメントを外してやります。

net.ipv4.ip_forward



8.APカーネルのインストール
ここまで長々とBSP周りの設定をしてきました。ここからやっとAPまわりの設定に入ります。4項でDLしておいたAPカーネルを、5項で準備しておいたAPカーネル用システムにインストールしてやります。


sudo dpkg -i --root=${APROOT} \
ap-linux-image-2.6.32-art-generic_20130227_i386.deb \
ap-linux-headers-2.6.32-art-generic_20130227_i386.deb



9.AP用システムの整備
まだまだ続きます。
(1)AP用システムへ移動(rootで入ることに注意)
# chroot ${APROOT}
(注:${APROOT}が/となり、このシステムのhostsファイル等の設定を行います)

(2)AP用システムのrootのpasswdを設定してやる。

(3)AP用システムの/etc/hostsにて、${hostname}-${APNAME}でホスト名を設定してやる。

(4)/etc/default/console-setup 中のACTIVE_CONSOLESをコメントアウトする。

(5)仮想シリアル端末からのログインを可能にする。

# cd /etc/init
# sed s/tty1/ttyBSP0/ tty1.conf > ttyBSP0.conf
# rm tty?.conf
# cd ..
# sed -i s/ttyS0/ttyBSP0/ securetty


(6)ureadaheadを停止する。

# cd /etc/init
# mv ureadahead.conf ureadahead.conf.bak
# mv ureadahead-other.conf ureadahead-other.conf.bak

(注:ureadaheadはlinux起動を早めるための先読みモジュールです。リアルタイム動作しようとしているので、こういうタイミングに影響が出そうなのは止めといた方が無難でしょう。起動してしまえば関係ないとは思うんですが、なくてもリアルタイム動作には影響しないし、悪さしかしないでしょうから。)


10.AP用のメモリの設定
さて、またBSP側の設定に戻ります。BSPのブート時にカーネルに起動オプションを設定して、AP用のメモリを確保してやらないといけません。

apmem:APに割り当てる低位メモリの領域(複数のAPがある場合はカンマで区切って)

aphighmem:APに割り当てる高位メモリの領域

ampshm:共有メモリに割り当てる低位メモリの領域(APが複数あろうと領域は一つだけです)

maxcpus:BSPカーネルが占有するコア数

どのくらいが適当なのかわからないので、とりあえず以下の設定で動かしてみました。

apmem=300M aphighmem=400M ampshm=100M

ここで「低位メモリ」って何?という意味がわからないと、どれくらいの領域を割り当てたらいいのか見当もつきません。「低位メモリ」とは、Linuxでは物理アドレスの0x00000000を仮想メモリの0xc0000000に割り当てることがほとんどです。つまり仮想アドレスの0xc0000000~0xffffffffの1GBは、物理メモリの最初の場所に配置されることになり、ここを「低位メモリ」と呼びます。
それでここが重要なんですが、Linuxでは複数のプロセスが独自の仮想メモリをもらい動作しますが、この「低位メモリ」は各プロセス共通に割り当てられます。つまり各プロセスがOSのサービスとデータをやりとりしようとしたり、OSのプロセスなんかはこの「低位メモリ」内で動くことになります。
つまり、BSPカーネルとAPカーネルは独自にこの「低位メモリ」領域がないと動けないため、それぞれに動作に必要なだけのメモリを割り当てておかないといけません。とはいっても、どれくらいあれば必要なだけあるかなんて、当該カーネルが動くときにロードするモジュールにもよるので一概に言えません。(特にリアルタイム制御したい、なんて目的なんで外部との専用通信モジュールが必要になることもあるでしょうし)なので適当にとしか言えないのが、つらいところです。
なおうまくメモリ領域が設定できたかは、BSP起動後に/proc/iomemを見てやれば確認できます。


11.APのブート
ここまできてやっとAPの起動ができます。以下のコマンドでインストールしたAP用カーネルが起動し、9(5)で設定した仮想シリアル端末からログインメッセージがでます。


# ifup ap0
# apboot ${APROOT}/boot/vmlinuz-2.6.32-art-generic rw \
ip=${APIP}:${BSPIP}:${BSPIP}:::bsp:p2p \
nfsroot=${BSPIP}:${APROOT},nolock


APが複数ある場合は、apbootのオプションで番号を指定できます。デフォルトは0から始まる番号です。


と、ここまでAPのブートまではできるようになりましたが(できたと思います・・・)、仮想シリアル端末が接続できない状態です。そのうち動くようになったら、また書きます。

追記:
11項でapbootする前に、以下のコマンドでシリアル端末を開いておきます。

sudo screen /dev/ttyAP0

そうするとapbootでAPが起動するときのログが表示されてきます。そこでわかりましたが、起動に失敗してました!ログを見てると、どうもNFSマウントのところで失敗しているようなんですが、なんかap0ap1が混在してる?そういやapbootでAP0として起動してるのに、NFSの設定やらhostsファイルやらAP1で定義してちゃあかんでしょ!
ということでそこを修正、だいぶ起動シーケンスが進むようになりましたが、今度はAP0からBSPへのネットワークが届かないとのこと。どこかルータの設定に問題があるようです。先は長いです。(しかしAPの起動って、数十秒単位で結構時間かかるのね・・・)

結果:
やっと動きました。ルータの設定で最初APIPとBSPIPを同じネットワークアドレスにしたのがまずかったのかと思ったんですが、それでも状況は変わりません。(でもこれはまずいと思います)
APの起動ログをよく見ると、どうもNFSのマウントでBSP側からの応答がないということらしいということで、BSPのNFSサーバ周りの設定を見直しました。デフォルトだとUbuntuのデスクトップ版ではサーバ関係のパッケージ何も入っていないので、後からnfs-kernel-server, nfs-commonを追加インストールしましたが、どこか問題があったようです。手動でnfsdを動かしてやろうと、

sudo /etc/init.d/nfs-kernel-server restart

とやると処理が固まってしまい、戻ってきません。いやこれは明らかにおかしいだろうとネットをググってみると、どうもportmapが動いていないとこうなるようです。psコマンドで見ると、確かに動いてません。設定のどこに問題があるのかわかりませんが、ブート時にportmapが起動してくれなくて、そのためnfsdも動いてなかったようです。そこでとりあえず手動でこのあたりを起動して、再度apbootしたら、あっさり動いてくれました。先に起動に時間がかかるといってたのは、NFSのマウントでtime-outを待っていたせいでした。

ART-Linuxの実験 インストール(その1)

ART-Linuxとは産総研で研究されている、Linuxのリアルタイム版です。(昔、RT-Linuxというのがあったけど、公開の仕方に問題がありかなり揉めたよね~ 知ってる人はかなり年季の入った人だと思うけどw)
そんで以前から考えてたんですが、ここ数年マルチコアなCPUが増えました。基本Linuxは複数のCPUがあってもそれらは平等に扱いますが、「リアルタイム制御用のコアを設定できたら便利じゃないか?」と思ってたら、ART-Linuxがそれをつい最近(2013年3月)に発表してくれました。これはぜひとも試してみようと思い、記録をメモしておきます。

1.ART-LinuxのインストールするLinuxの準備
ART-LinuxはUbuntu-10.04(Lucid)のKernelを改造したもののようです。まずLucidをDLしてきて、それをマルチコアなマシンにインストールします。(手元で実験に使えそうなのがCore2Duoのマシンしかなかったので、これで。)32bit版をインストールしてください。


2.ART-Linuxのインストール(BSP)
1項でインストールしたUbuntuのkernelを産総研のART-LinuxのHPからDLしてきます。


linux-image-2.6.32-art-generic_20130227_i386.deb
linux-headers-2.6.32-art-generic_20130227_i386.deb
linux-source-2.6.32-art_20130227_all.deb


PAE(メモリ拡張用)とかありますが、今回はベーシックなものを。(ちなみにART-Linuxには32bitしかありません。とりあえずリアルタイムで動かす制御用アプリで64bitが必要な類のものは思いつかないのでいいと思いますが。)
これらをインストールします。


sudo dpkg -i linux-image-2.6.32-art_20130227_i386.deb linux-headers-2.6.32-art_20130227_i386.deb linux-source-2.6.32-art_20130227_all.deb


これでART-Linux(BSP用)のkernelがインストールされ、それ起動用にgrubの設定も追加してくれます。(つまり、元々のUbuntuも起動できます)

注:BSPというのはLinuxの通常業務を行うプロセスのことで、最低1コアは割り当てる必要があります。インストール直後はBSPに何コア割り当てるとかのkernel起動パラメータを設定してありませんので、この場合は2コアで動いてしまいますが、後々AP(リアルタイム用コア)を動かすまではそれで構いません。


3.サンプルプログラムの実行
さてインストールが成功したか確認してみます。BSPでもとりあえずこれまでのART-Linuxの機能はあるようです。(基本は厳密なタイマ管理ができるか、ということになると思いますが。BSPがアプリで占有できないので、ちょうどアプリが動きたいときにシステム作業が発生してしまうと止めようがないでしょうが、システムコールに影響されない厳密なタイマがあるだけでリアルタイムのアプリを書くのは楽になります)


#include <stdio.h>
#include <linux/art_task.h>
#include <time.h>
#include <sys/time.h>

double gettimeofday_sec()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return (tv.tv_sec + (double)tv.tv_usec*1e-6);
}

void process(void)
{
  register int i;

  double start_t1;
  double now_t1;

  start_t1 = gettimeofday_sec();

  art_enter( ART_PRIO_MAX, ART_TASK_PERIODIC, 1000000 );
  /* Real Time Task Start */
  for (i=0; i<100; i++) {
    art_wait();
    
    now_t1 = gettimeofday_sec();

    printf("[%d] %10.30f\n", i, (now_t1 - start_t1));
  }
  putchar('\n');

  art_exit();
  /* Real Time Task exit */
}

int main(void)
{
  process();

  return 0;
}

以下のようにビルドします。

$ gcc -Wall -O sample1.c /usr/lib/art_syscalls.o

オリジナルのサンプルに少し追加しました。art_wait()で1秒間を正確にwaitしてますが、そこからほんの少しですがコードが動きます。その処理時間が累積するのかどうか、それを見るために実時間を表示しました。
大体、100回loopすると以下のような感じになります。

[99] 99.9835

あれ?なんか少しだけ早く回ってる?ちょっと予想とずれてしまいましたが、art_wait()の精度の問題なのか、gettimeofday()の問題なのか、長時間(1時間くらい)のサンプルを書いてみるか、外部に信号を出して計測してみないとわかりません。

追記:
その後、さらに設定をいろいろと変えて実験してみました。結論から言うと、

①上記の結果はインストール途中の結果であり、BSPは2コアの設定になっていた。またAP用のメモリ設定(今後、書きます)もしていなかった。ただし、gnomeのdesktopは動いていた。

②BSP=1にして実験すると、[99] 100.052等安定して処理が遅れるようになっていった。現在のLinuxのタスクスイッチが1ms、しかもデフォルトのART-Linuxの割り込み最短時間が1msなのを合わせて考えると、それが一番なっとくのいく結果と思われる。

③さらにART-Linuxの割り込み最短時間=500usにしてみたが、さらに安定して毎回1ms程度遅れるようになった。(予測しやすくなった)

サンプルが1秒ごとに1行出力するよ、という意味ではないような気がします。もっともこちらもART-Linuxのタイマ管理をよく勉強せずにサンプルを使ってしまいましたが、正確なタイマがあってもこうなるでしょう。本当に1秒周期で1行出力したいなら、タイマで0.99秒ほどまち、それからは1秒たったかloopでチェックするようにしないとだめでしょう。逆に最初の結果(早く動いてしまう)ほうが、リアルタイムのプログラムを作るうえでは、動作予測がしづらく使いづらいです。デフォルトのままだと、gnomeの割り込み処理や、Core2DuoやNvidia(グラフィックボードがこれ使ってます)のドライバ周りの割り込み等、リアルタイムを乱す要因がたくさんあり、変な結果になったと思います。(ゲーム程度の60Hz程度の周期でリアルタイム性が確保できればいいというならこれでもいいですが、本気で1ms周期の制御したいならCLIベースで動作させないといけないでしょう。)