(第26回)リアルタイム性について考える(その1:リアルタイム性って何?)

2007/12/10

あなたは 人目のお客様です.

しばらく Linux 対応をしていたので連載のほうが止まっていたが, 今回から数回に分けて,リアルタイム性について考えてみよう. ほんとうは1回で説明したかったのだけど,まあいろいろ考えなければ ならないこともあるし,KOZOSにもいろいろと修正が必要なので, 数回に分けることにした.

まずは「その1」として,「リアルタイム性」の一般的な話をしようと思う.

組み込みOSを考える際に必ずと言っていいほど出てくる言葉に 「リアルタイム性」というものがある. このOSはリアルタイムOSだとかリアルタイム性は無いとか, そんなふうに使われる言葉だ. では,リアルタイム性とはいったいどういうことを言うのか?

まあまずよく言われることなのだけど,「リアルタイム = 軽くて速い」 ということではない.まあたいていのリアルタイムOSは軽くて速いのだけど, 軽くて速いOSをリアルタイムOSというわけではない. たとえ高速でもリアルタイム性の無いOSもあれば, 低速だがリアルタイム性のあるOSもある.

リアルタイム性を一言で言うならば, 「ある入力を与えたときに,応答までにかかる時間が見積もれる」 ということだ.

で,次によく言われるのが,「リアルタイムOSの上でアプリを書けば, 必ずリアルタイムになる,というわけではない」 ということだ.まあこれは例えばC++やJavaで書いたところで必ず オブジェクト指向になるわけではない,ということと同じだ. 書き手がその意味をきちんと理解して,意識して書くのでなければ意味は無い, ということだ.

ということでリアルタイム性というのは,正確には, 応答時間を見積もるための手段をOSが提供していて, アプリを気をつけて書くならば,応答時間を*必ず*確保できる, ということだ.

で,このようなリアルタイムOSというのがどこで使われるのかというと, 制御系などの,いわゆる「リアルタイム性が必要な分野」で使われることになる.

たとえば自動車のエアバッグ制御を,汎用OSである Linux で行ったら どうなるだろうか? (あくまで「たとえば」だよ)

Linux は仮想メモリシステムを持っており,プロセス単位での動作をする. このためプロセスの切替え(タスクのディスパッチ)時には, 仮想メモリのマッピングの切替えが行われる. さらにメモリが不足している場合には自動的にハードディスクに退避(ページスワップ) される.しかしプロセスからすれば,現在参照しようとしているメモリが 実メモリ上にあるのか,ハードディスク上に退避されているために復帰する 必要があるのかはわからない.もしもハードディスク上に退避されている場合には, 以下のような動作が起きる.

このような処理はプロセスが知らないうちに Linux が裏で勝手にやってくれる. プロセス(アプリ)側では,たとえば
printf("%d", i);
のようにして参照した変数iの値(を格納しているメモリ)が,実メモリ上にあるのか, ハードディスクのスワップ領域上にあるのかは,知ることはできないし, 知る必要もない.何も考えずにiの値を見れば,あとはOSが裏でよろしくはからって くれるのだ.これが「仮想メモリ」という動作であり,コンピュータ史上の 3大発明のうちのひとつだとぼくは勝手に思っている. (ちなみに残りの2つはノイマン型と割り込みだ)

しかし,これはリアルタイム性という点で見れば問題だ. なぜならば,ふつうにプログラム上で

printf("%d", i);
とか書いたときに,はたしてiの値が実メモリ上にあるためにすぐに読み取れるのか, ハードディスク上に退避されているために読み取るのに時間がかかるのかが わからないからだ. 他プロセスがどれくらいメモリを食っているかとかによって ページスワップのタイミングは変わってくるので, ページスワップがどのように行われるかというのは,予測することは基本的に難しい. まあ相当頑張れば予測くらいはできるのかもしれないが,少なくともそれを予測して システムを設計するようなことは現実的ではない. このへんはメモリキャッシュが利用されるとリアルタイム性を見積もることが 困難になるのと同じことだ. で,もしもページスワップが発生してしまったら, 動作速度は極端に遅くなっておそらく期待した時間内には処理を完了できない. まあ確率的には低いのかもしれないが,リアルタイム性という点で見れば, それが100回に1回でも1億回に1回の確率でも,リアルタイム性が無いという点では 同じことだ.なので「Linux にはリアルタイム性は無い」ということになる.

で,本題に戻るが,たとえば Linux で自動車のエアバッグ制御を行ったら どうなるだろうか? まあ実際にはそのようなことはないのだけど, ここでは説明のために,Linux をインストールしたハイスペックなPCで エアバッグ制御をする,ということを考えてみる.

PC自体が高速なので,基本的には,十分な時間でエアバッグを制御できるかも しれない. しかし衝突センサが衝突を感知したときに,エアバッグを制御するためのアプリが 利用しているメモリ領域がページスワップによって,たまたまハードディスク上に 退避されていたらどうなるか? アプリがそのメモリ領域を参照した際にはメモリ参照例外が発生し, OSがハードディスク上からメモリの内容を復旧してからアプリが動作を再開することに なるので,動作はきっと100倍以上(100倍,なんていうような単位ではないような 気もする)遅くなる.これでは,エアバッグはまともに作動してくれないだろう. すでに衝突してしまってから数秒後にようやくエアバッグが作動,ということにも なりかねない.

これは100万回に1回しか発生しないような事象なのかもしれない. 残りの99万9999回は,ずっと高速に動作するのだろう. ところがこの解決策として,例えばCPUをもっと高速にするとか,メモリを大量に 積んでページスワップが発生しにくくするとかいうのでは,解決にはならない. まあCPUをもっとハイスペックにして,メモリも10倍の量を積めば, 問題は発生しにくくなるのかもしれない.しかしそれは100万回に1回の確率が, 単にもっと低くなるだけで,ゼロになるわけではない.発生する可能性がある以上, どちらにしろリコールにはなると思う.ていうかそんな車,こわくて乗りたくない.

たとえば「この車のエアバッグシステムはほとんどの場合はうまく作動しますが, まれにうまく作動しない場合があります.ただ,それは1万回に1回ていどの確率 なので問題はありません」なんていう車があったら,その車に乗るだろうか. まあ即リコールだと思う.リアルタイム性が無いというのは、そーいうことなのだ。 このばあい,確率の大きさは,OS的には実はあまり重要ではない. うまく作動しないのが100回に1回だろうが100万回に1回だろうが, 可能性がある時点でダメだからだ.

たとえば Windows を使っていて,普段はキーを押せばさくさくと反応するが, ちょっと放置しておいてキーを押すと,キーを押した瞬間にHDDがういーんとかいって 動き出して,しばらくしてやっとキーにアプリが反応する,というような経験は 誰でもしたことがあるだろう.これがエアバッグ制御だったらどうなるか, ということを考えてみてほしい.

これはそもそもページスワップが発生するというOSの構造上の問題なので, CPUを速くするとかメモリをいっぱい積んでページスワップを起きにくくするとかいう ことではなく,ページスワップをしないOSを採用する,という解決策を取らなければ ならない. 衝突センサが反応した際に,特定の時間内に必ず応答してくれるような構造を持つ OSを採用しなければならない.これが,リアルタイム性ということだ.

なので,たとえば横軸が応答時間,縦軸が発生確率のグラフを書いた際に

のように尻スボミになっていて,裾野が広くていつになったら確率がゼロになるのか わからないようなグラフでは困る.これは,たとえ確率が限りなくゼロに近付いて いったとしても,ゼロにならない限りはダメだ. これでは,「これこれの事象が発生した際に,xxマイクロ秒以内に応答できること」 というシステムを設計できない.いくら確率が低いとはいえゼロではないため, いつまでに反応するのか,確実な応答時間が見積もれないからだ.

そうではなく

このように,ある位置で完全に確率がゼロになっていないとダメなのだ. これならば,応答時間が足りなければCPUを高速化したりプログラムをチューニング することで,応答時間を保証することができるので, 「これこれの事象が発生した際に,xxマイクロ秒以内に応答できること」 というような要求に対して,システムを設計することができる. これが,リアルタイム性ということだ.

今回はリアルタイム性の一般的な説明をした.次回からはKOZOSのリアルタイム性に ついて考えてみたい.


メールは kozos(アットマーク)kozos.jp まで