マルチコアCPUでは
スケジューリングのルールも変わる
スケジューリングに関わる重要なもうひとつの要素は、メモリー管理だ。メモリーが足りなくなると、仮想記憶を管理するメモリーマネージャーは、使われていないページをスワップアウトしてメモリーを再割り当てする(関連記事)。このときに、同じぐらい使われていないページがあったらどのプロセスを選ぶか、あるいはプロセスの管理しているメモリーのなかでどのページを選ぶかは、メモリーマネージャーの仕事となる。
しかし、現在動いているプロセスや次に起動されそうなプロセスのメモリーをスワップしてしまうと、これらを再起動するときに時間がかかってしまう。そのためI/O待ちなど何らかの理由で、しばらくの間動かないと思われるプロセスを選択する必要がある。スケジューラーの挙動を予想しなければ、スワップしても支障のないプロセスを見つけられない。
逆に言えば、スワップアウトされたページを持つプロセスは、しばらく動けなくなる可能性がある。また再開されたとしても、スワップインのためにファイルが読み込まれるので、結局I/O待ちと同じ状態になる。メモリーマネージャーはプロセスの実行を制御するスケジューラーの、一部の役割を担っているとも言えるわけだ。
多くのOSでは、プロセスに「優先度」をつける。優先順位を付けることで重要なプロセスや、一定時間内に繰り返す必要があるプロセスを優先して実行させる。しかし優先度だけを見ていると、場合によっては長い間、タイムスライスが回ってこないプロセスが出てしまう可能性がある。
優先度は重要だが、長い時間で見れば各プロセスにはある程度、公平に実行時間が配分されなければならない。優先度だけを見てタイムスライスを分けると、負荷の低いときには最も優先度の低いプロセスも実行させることができるが、負荷が高くなったときには、優先度の高いプロセスしか実行されない可能性がある。スケジューラーは、こうした長期的な視点から、優先度と実行プロセスを管理しなければならない。
また、以前解説したように、プロセスよりも小さいスケジューリングの単位に「スレッド」がある(関連記事)。ひとつのプロセスが、複数のスレッドを実行している可能性があるわけだ。そうなると、その複数のスレッドやメインスレッド(プロセス)の実行に関して正しく考慮しないと、スレッドの処理結果をほかのスレッドが待っているような場合、待っているスレッドばかりになってしまって、処理する側が後になるような可能性もある。あるいは、スレッド側で処理が終わったのにメインスレッド側へタイムスライスが回らないので、処理の終わったスレッドを終了できないといった堂々巡りになる可能性もある。
つまり、同一プロセス内のスレッドにはある程度の依存関係があるので、優先度などの実行再開に関する条件が同じなら、同一のプロセスに所属するスレッドを続けて実行させたほうが、処理効率は高くなる(図2)。プロセスが終了すれば占有していたリソースが解放されるし、メモリーなどにも余裕が出る可能性もあるので、さっさと終わらせた方がいいわけだ。
最近のPC用プロセッサーはマルチコアが当たり前で、マルチプロセッサーでもある。またCore iシリーズやAMD FXなどは、ハードウェア的にひとつのプロセッサーコアで同時に2スレッドを実行する「SMT」(インテルではハイパースレッディング)を装備している。この場合、同一プロセスに所属するスレッドを実行するなら、同じコアや同じプロセッサーパッケージを使うほうがキャッシュが共有できるため、高速化できる可能性がある(図3)。キャッシュミスが多発すると、その分処理性能が落ちてしまうからだ。
またCore iプロセッサーやAMD FXでは、プロセッサーパッケージごとにメモリーコントローラーがあり、そこにメモリーが接続されている「NUMA」構造となっている。そのためマルチプロセッサー環境の場合、自分に接続されているメモリー内にあるプログラムやデータを使う方が、ほかのCPUに接続されたメモリーよりも効率がいい。
プロセッサーコアとプロセスとの結びつきを、「Affinity」(親和性、親近感)と呼ぶ。こうした理由もあって、Windows 7などマルチコアCPUに対応したWindowsでは、タスクマネージャーがプロセスごとに、実行するプロセッサーコアを固定できる。デフォルトは「すべてのプロセッサー」である。APIも用意されており、スレッドやプロセスを実行するコア(複数)を、明示的に指定できる。
そのほかにも、プロセスの起動もスケジューラーに関係する。なぜならプロセスが起動するということは、スケジューラーの管理下にそのプロセスが入るからだ。そのためプロセス起動の処理では、準備を終えたあとはスケジューラーに起動処理を任せてしまうこともある。逆に、プロセスの起動段階ではさまざまな準備が行なわれるので、処理負荷も高い。このときにはプロセスに割り当てるCPU時間を多くすることで、起動がスムースになる。こうしたスケジューラーの細かい調整が、体感するパフォーマンスを向上させるのに役立つわけだ。
この連載の記事
-
第13回
PC
ARM版Windows 8実現の布石となったWindows 7の「MinWin」 -
第12回
PC
アプリがWindowsの機能を使うには? APIとDLLの仕組み -
第11回
PC
マルチコアCPUの消費電力はスケジューリングで変わる? -
第10回
PC
AMD FX向けにパッチで修正 スケジューラーが抱える難題 -
第8回
PC
意味の違いがわかる? タスクとプロセスとスレッド -
第7回
PC
Windowsのメモリー管理をx86の仕組みから読み解く -
第6回
PC
メモリー不足を根本的に解決する64bit OSの仕組み -
第5回
PC
Windows 8でMetro Styleアプリを動かす「WinRT」 -
第4回
PC
Windowsを動かすデバイスドライバーの仕組み 前編 -
第3回
PC
OSの仕事はハードウェアをアプリから「隠す」こと? - この連載の一覧へ