(注意)このブログは本家のほうの文章部分のみの転載です.ソースコードの配布,画像などについては本家のほうを参照してください.文章中のリンク先は面倒なのですべて本家のほうに変換してしまっているのでご注意ください.
しばらく Linux 対応をしていたので連載のほうが止まっていたが,今回から数回に分けて,リアルタイム性について考えてみよう.ほんとうは1回で説明したかったのだけど,まあいろいろ考えなければならないこともあるし,KOZOSにもいろいろと修正が必要なので,数回に分けることにした.
まずは「その1」として,「リアルタイム性」の一般的な話をしようと思う.
組み込みOSを考える際に必ずと言っていいほど出てくる言葉に「リアルタイム性」というものがある.このOSはリアルタイムOSだとかリアルタイム性は無いとか,そんなふうに使われる言葉だ.では,リアルタイム性とはいったいどういうことを言うのか?
まあまずよく言われることなのだけど,「リアルタイム = 軽くて速い」ということではない.まあたいていのリアルタイムOSは軽くて速いのだけど,軽くて速いOSをリアルタイムOSというわけではない.たとえ高速でもリアルタイム性の無いOSもあれば,低速だがリアルタイム性のあるOSもある.
リアルタイム性を一言で言うならば,「ある入力を与えたときに,応答までにかかる時間が見積もれる」ということだ.
で,次によく言われるのが,「リアルタイムOSの上でアプリを書けば,必ずリアルタイムになる,というわけではない」ということだ.まあこれは例えばC++やJavaで書いたところで必ずオブジェクト指向になるわけではない,ということと同じだ.書き手がその意味をきちんと理解して,意識して書くのでなければ意味は無い,ということだ.
ということでリアルタイム性というのは,正確には,応答時間を見積もるための手段をOSが提供していて,アプリを気をつけて書くならば,応答時間を*必ず*確保できる,ということだ.
で,このようなリアルタイムOSというのがどこで使われるのかというと,制御系などの,いわゆる「リアルタイム性が必要な分野」で使われることになる.
たとえば自動車のエアバッグ制御を,汎用OSである Linux で行ったらどうなるだろうか? (あくまで「たとえば」だよ)
Linux は仮想メモリシステムを持っており,プロセス単位での動作をする.このためプロセスの切替え(タスクのディスパッチ)時には,仮想メモリのマッピングの切替えが行われる.さらにメモリが不足している場合には自動的にハードディスクに退避(ページスワップ)される.しかしプロセスからすれば,現在参照しようとしているメモリが実メモリ上にあるのか,ハードディスク上に退避されているために復帰する必要があるのかはわからない.もしもハードディスク上に退避されている場合には,以下のような動作が起きる.
のようにして参照した変数iの値(を格納しているメモリ)が,実メモリ上にあるのか,ハードディスクのスワップ領域上にあるのかは,知ることはできないし,知る必要もない.何も考えずにiの値を見れば,あとはOSが裏でよろしくはからってくれるのだ.これが「仮想メモリ」という動作であり,コンピュータ史上の3大発明のうちのひとつだとぼくは勝手に思っている.(ちなみに残りの2つはノイマン型と割り込みだ)
しかし,これはリアルタイム性という点で見れば問題だ.なぜならば,ふつうにプログラム上で
とか書いたときに,はたして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のリアルタイム性について考えてみたい.
しばらく Linux 対応をしていたので連載のほうが止まっていたが,今回から数回に分けて,リアルタイム性について考えてみよう.ほんとうは1回で説明したかったのだけど,まあいろいろ考えなければならないこともあるし,KOZOSにもいろいろと修正が必要なので,数回に分けることにした.
まずは「その1」として,「リアルタイム性」の一般的な話をしようと思う.
組み込みOSを考える際に必ずと言っていいほど出てくる言葉に「リアルタイム性」というものがある.このOSはリアルタイムOSだとかリアルタイム性は無いとか,そんなふうに使われる言葉だ.では,リアルタイム性とはいったいどういうことを言うのか?
まあまずよく言われることなのだけど,「リアルタイム = 軽くて速い」ということではない.まあたいていのリアルタイムOSは軽くて速いのだけど,軽くて速いOSをリアルタイムOSというわけではない.たとえ高速でもリアルタイム性の無いOSもあれば,低速だがリアルタイム性のあるOSもある.
リアルタイム性を一言で言うならば,「ある入力を与えたときに,応答までにかかる時間が見積もれる」ということだ.
で,次によく言われるのが,「リアルタイムOSの上でアプリを書けば,必ずリアルタイムになる,というわけではない」ということだ.まあこれは例えばC++やJavaで書いたところで必ずオブジェクト指向になるわけではない,ということと同じだ.書き手がその意味をきちんと理解して,意識して書くのでなければ意味は無い,ということだ.
ということでリアルタイム性というのは,正確には,応答時間を見積もるための手段をOSが提供していて,アプリを気をつけて書くならば,応答時間を*必ず*確保できる,ということだ.
で,このようなリアルタイムOSというのがどこで使われるのかというと,制御系などの,いわゆる「リアルタイム性が必要な分野」で使われることになる.
たとえば自動車のエアバッグ制御を,汎用OSである Linux で行ったらどうなるだろうか? (あくまで「たとえば」だよ)
Linux は仮想メモリシステムを持っており,プロセス単位での動作をする.このためプロセスの切替え(タスクのディスパッチ)時には,仮想メモリのマッピングの切替えが行われる.さらにメモリが不足している場合には自動的にハードディスクに退避(ページスワップ)される.しかしプロセスからすれば,現在参照しようとしているメモリが実メモリ上にあるのか,ハードディスク上に退避されているために復帰する必要があるのかはわからない.もしもハードディスク上に退避されている場合には,以下のような動作が起きる.
- プロセスがメモリ参照を行う.
- しかしそのアドレスはハードディスク上に退避されており仮想メモリ上に マッピングされていないため,メモリ参照例外(Segmentation Fault)が発生する.
- OSは Segmentation Fault が発生したらそのアドレスが実際に利用できる (が,ハードディスク上に退避されているためにまだ直接参照できない)のか, もしくは不正なアクセスなのかを調べる.(不正な場合にはプロセスに SIGSEGV を 送り,ふつうはここで Core Dump してプロセスが落ちる)
- ハードディスク上に退避されている領域ならば,ハードディスク上から実メモリに ロードする.
- ロードしなおした領域をプロセスの仮想メモリにマッピングし,プロセスの実行を 再開する.
- プロセスは何も気づかずに再度メモリ参照を行う.今度は成功し,メモリの値が 読み取れる.
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のリアルタイム性について考えてみたい.