リアルタイムなLinux
リアルタイム性を考えてみる
・調査:
PREEMPT_RTのパッチってどうなってるんだろう、と思ってkernel.org見てみたらんなもんなさそうだった。
どうもCFSになってから(?)スケジューラにリアルタイムポリシーというものがあるようだ。
man sched_setschedulerすればいろいろわかる。日本語のmanってわかりやすくてイイネ!
以下man sched_setschedulerからの引用。
sched_setscheduler() は pid で指定された ID を持つプロセスの
スケジューリング・ポリシーやそれに関連するパラメータを設定す
る。pid が 0 の場合は 呼び出したプロセスのスケジューリング・
ポリシーとパラメータが設定される。 引き数param の解釈は選択さ
れたポリシーによる。 現在のところ、Linux では 以下に示す「通
常」(リアルタイムでない)スケジューリング・ポリシーが サポート
されている。
SCHED_OTHER 標準の、ラウンドロビンによる時分割型のスケジュー
リング・ポリシー。
SCHED_BATCH 「バッチ」形式でのプロセスの実行用。
SCHED_IDLE 「非常に」低い優先度で動作するバックグラウンド・
ジョブ用。
どの実行可能プロセスを選択するかについて、より正確な制御を必
要とする 時間の制約が厳しい特別なアプリケーション用として、以
下の「リアルタイム」ポリシーもサポートされている。
SCHED_FIFO ファーストイン、ファーストアウト型のポリシー。
SCHED_RR ラウンドロビン型のポリシー。
どうも、SCHED_FIFO/RRというものを使えばいいらしい。FIFOだと間違えて無限ループするプログラム書くと死ぬらしいので、RRが普通なのかな?あと、もっと下の方にはこんな記述もあった。
本流の Linux カーネルでのリアルタイム機能
カーネル 2.6.18 から現在まで、 Linux は徐々にリアルタイム機能
を備えつつあるが、 これらの機能のほとんどは、 Ingo Molnar,
Thomas Gleixner, Steven Rostedt らによって開発された、 以前の
realtime-preempt パッチからのものである。 これらのパッチが本
流のカーネルに完全にマージされるまでは (マージの完了はカーネ
ル 2.6.30 あたりの予定)、 最高のリアルタイム性能を達成するに
は realtime-preempt パッチを 組み込まなければならない。これら
のパッチは
patch-kernelversion-rtpatchversion
という名前で、
http://www.kernel.org/pub/linux/kernel/projects/rt/ からダウ
ンロードできる。
このパッチが適用されず、かつパッチの内容の本流のカーネルへの
マージが 完了するまでは、カーネルの設定では
CONFIG_PREEMPT_NONE, CONFIG_PREEMPT_VOLUNTARY,
CONFIG_PREEMPT_DESKTOP の 3つのプリエンプション・クラス
(preemption class) だけが提供される。 これらのクラスでは、最
悪の場合のスケジューリング遅延がそれぞれ全く減らない、いくら
か減る、かなり減る。
パッチが適用された場合、またはパッチの内容の本流のカーネルへ
のマージが 完了した後では、上記に加えて設定項目として
CONFIG_PREEMPT_RT が利用可能になる。この項目を選択すると、
Linuxは通常のリアルタイム・オペレーティングシステムに変身する。
この場合には、 sched_setscheduler() で選択できる FIFO とRR
のスケジューリング・ポリシーは、 真のリアルタイム優先度を持つ
プロセスを最悪の場合のスケジューリング遅延が最小となる環境で
動作させるために使われることになる。
もしかして・・・CONFIG_PREEMPT_RTのオプションつけてRealtimeポリシーつかえばOKなのでは???realtimeパッチの内容をちょっと読んでみたい。
・実験:
とりあえずはじめに普通のカーネルである自分のPCで少し調査してみた。ちなみにuname -aの結果は以下。
調査の内容は以下の2つ。
- 負荷をかけた状態で、usleep(10000)をする。このとき、schedのポリシーをかえる
- 負荷をかけた状態で、sigactionをする。(10ms) つまり(ソフトウェア)タイマ割り込み。
負荷のかけかたは、以下のコマンドを2つ(2コアなので)実行させた。CPU消費率は100%に張り付いていた。
for (( i=0 ;; )) do i=$i+1; done
1: 縦軸は秒、横軸は何回目の処理か
あれ・・・1桁ずれてる。プログラムの計時部は以下。
for ( int i=0; i<times; i++ ) { if ( gettimeofday( &tv, NULL ) ) { perror( "gettimeofday" ); return 1; } now = tv.tv_sec*1000000 + tv.tv_usec; printf( "0.%-6d\n", now-prev ); prev = now; if ( usleep( 10000 ) ) { perror( "usleep" ); return 1; } }
まちがってないよね...?なんでだろ。これは要解明。
ただ、RR(Round Robin)ではかなり綺麗に100msを維持している。
平均と標準偏差求めるべきでしたね。あとでやろ。
2:縦軸はus, 横軸は何回目か
やっぱりSCHED_RRはつよいっすね。
・結論:
この調査からわかることは、実はkernel3.5ではかなりきちんとリアルタイムなプロセスがリアルタイムで動く、ということである。
ただ、今回はリアルタイムなプロセスを1つにした(システムがどれくらいそういうプロセスを持つのかも調べる必要があるが)ので、複数ある場合にも正しい結果を得られるかどうかを調査する必要もありそうである。
また、通常の状態でこれだけの結果を得られてしまったので、CONFIG_PREEMPT_RTの設定でどう変わるのかがよくわからない。それでどう変わるのか、カーネルのソースも見て確認したい。
・資料:
いいかんじに説明が書いてあったページを紹介してみる。
IBMのdeveloperworksってやつ。くわしくてよいがちょっと古い。(CFSになる前)
シグナルとコールバックというものについて説明がある。まだ呼んでない。笑
早く課題決めなきゃ。。。