プロセスその7

問題は、この「適度なWorking Set Sizeってどの位だ?」という話が一概に言えないこと。確かVMSの4.x~5.xの時代は、Page Fault Rateが100PFSを越えるとそろそろまずい、という話だったと記憶しているが、この数字は当時のVAXの構成などとも関係してくるから、現在の環境でこの数字をそのまま使うことはできない。ただ、Page Fileへのアクセス能力(帯域とレイテンシの両方)、およびPage In/Outのコストで限界となるPage Fault Rateは概ね決まってくると言ってよいから、例えばこれが今では10万PFSまでOKということにはなりにくいとは思う(*1)。このあたりはIDSにも、Inside Windowsにも具体的な数字はないが、ハードウェアの構成に合わせてこのあたりの閾値は変化できるような仕組みがあっても不思議ではない。

さてPage Faultが発生した場合、では不足した分をいきなり追加するのが好ましいか? というと、これまた考え物である。その不足が一時的に足りてないだけか、それともコンスタントに足りないのか、という見極めはこの時点では不可能である。いきなりWorking Set Sizeを増やすのは、他のプロセスへの影響を考えると好ましくない。そこで、Workin Set Sizeは序々に変化する仕組みがとられている。

図3:Working Setの調整

図3はこれを簡単に示したものだ。黒い実線がプロセスが実際に必要とするWorking Set Size、赤い実線が実際に割り当てられるWorking Set Sizeである。ある一定間隔(Quantum Tick)毎に、そのプロセスへのWorling Set調整を行うべきかどうか、を判断する。そのTick間のPage Fault Rateが閾値より高く、かつInvalid Pageが殆ど無いのであれば、これはメモリ不足ということで、Working Setを一定量(これがWSINC:Workin Set Incresementというパラメータで与えられる)増やす。逆にPage Fault Rateが基準より低く、かつInvalid Pageが一杯あるようなら、それはメモリが余っているという話になるので、今度はWorking Set Sizeをやはり一定量(こちらがWSDEC:Working Set Decresementというパラメータ)だけ減らす事になる。Page Fault Rateが基準以下だが、Invalid Pageも無いという話であれば、丁度充足しているということなので、Working Setの調整はなしである。厄介なのが、Page Fault Rateが十分高く、かつInvalid Pageも結構ある場合。例えば巨大な配列をメモリ中に確保し、これを片端から書き換えてゆくなんてケースだ。こうしたケースでは、判断が難しいことになる。意味があるかどうかはともかく、例えば1GB分のテーブルをメモリに取って、それに初期値を埋めてゆくなんてケースでは、多少Working Setを増やしてもPage Fault Rate削減には繋がらない。初期値0という話なら、まだDemand Zero Pageといったメカニズムもあるのだが、

unsigned long	*buffer;
unsigned long	lpCnt;

buffer = malloc( 1024*1024*256*sizeof( unsigned long ));
for( lpCnt = 0; lpCnt < 1024*1024*256; lpCnt++ )
        buffer[lpCnt]=lpCnt;

なんてコードを実行された日には、どうやってもPage Fault Rateを下げる事はできなくなる。そこで、こうしたケースではWorking Set Sizeを変更しないといったアプローチが取られるのが普通だ(*2)。

ただこれだけだと、ニーズがあればいつまでもWorking Setが増えかねない。例えば、

unsigned long	*buffer;
unsigned long	lpCnt;

for( ;; )
        buffer = malloc( 1024*( unsigned long ));

なんてコードを動かすと、直ぐにプロセス空間を使い切ってプログラムは落ちる事になるだろうが、その落ちるまでの間、延々とWorking Setを増やすことになってしまう。これを防止するためのメカニズムはちゃんと用意されている(続く)。

(*1) Page Fileを全部SRAMあたりで構成したSSD上に置き、これを超広帯域Interconnectで繋ぐ、なんて馬鹿げた構成をとれば、あるいは不可能ではないのかもしれないが。ただ1Page=4KBとして、毎Page Faultごとに1Pageだけ読み込み、かつシークが限りなく0という理想的な条件でも、Page Inに必要な帯域は10万PFS=10万×4KB~400MB/secということになる。SATA II-3Gでも追いつかない速度だし、実際にはPage Inの傍らでPage Outも発生してることを考えれば、実際には1GB/sec近い帯域が必要とされるわけで、大規模サーバー以外はここまで行くことは考えにくい。せいぜいが1万PFS程度が現実的な上限で、実際にはもっと少ないだろうと想像される。

(*2) 実装による。聞いた話では、Working Set AdjustmentにPriorityを付ける実装があるらしい。つまり、Page Fault Rateが閾値より高く、かつInvalid Pageが殆ど無い場合にはHigh Priorityとし、Page Fault Rateが閾値より高く、かつInvalid Pageも一杯の場合にはLow Priorityとする仕組みだ。System全体のFree Page Listのサイズを確認し、ある閾値以上Free Pageが余っていればHigh PriorityとLow Priorityの両方を実施し、閾値以下のFree Pageしかなければ、High Priorityのものだけを実施するというものだ。ただ当然これはWorking Set Adjustmentの複雑化を招くことになり、あまり一般的ではないそうだ。