5.6 仮想マシン
VMという言葉からイメージする仮想化は、CPUバイナリ互換性からJavaVM等まで色々なものがある。
だけど、ここで議論するものは、命令セットアーキテクチャ(ISA:interaction set architecture)の互換性についてのみとする。
このようなものを、システム仮想マシン(system virtual machine)と呼び、どんな物なのかはVMwareなどをイメージすると分かりやすい。VMの下のレイヤーにある仕組みをVMM:仮想マシンモニタ(あるいはハイパーバイザ)と呼び、プラットホーム側をホスト、仮想環境をゲストVMと呼ぶ。
この仮想マシンモニタは、非常にコンパクトになることが多い(1000ステップぐらいらしい!!)
VM環境でソフトウェアを動かす場合、CPU処理が多い場合はオーバーヘッドは少ないが、I/Oが増えると遅くなる。その理由はOSのシステムコール発行が増え、VMとしての仕事が増えるから。
VMMに求められる要件には以下の3つがある
ハードウェアリソース使用時の橋渡し 各ゲストVMの環境を分離する 各ゲストVMから仮想マシンモニタを保護する |
VMM自体はソフトウェアとして実装されるけど、VMMを作る上でCPU側にサポートして欲しい機能には、以下のものがある。これがないと、VMMはゲストVMを箱庭の中で飼うことが出来ない。
1.CPUにユーザモードと、システムモードがある事。 2.ユーザモードで特権命令が発行された場合、そのことを例外としてVMMがトラップできる事。 |
5.7 有限状態機械を用いた単純なキャッシュの制御
有限状態オートマトン(FSM)の考え方で、キャッシュ制御のコントローラを考えてみる話。
特にメモっときたい点が無かったので、省略。
5.8 並列処理と記憶階層:キャッシュ・コヒーレンス
マルチプロセッサ環境では、メモリのキャッシュ(L1,L2キャッシュなど)が各CPUに乗っている事になる。
ライトバックのキャッシュだった場合は、各CPUキャッシュ間で、保持している情報が異なる可能性が出てくる。これは非常に問題で、CPU1が保持しているキャッシュ(メモリに未反映)の情報をCPU2が使用する場合に、データの不整合が発生してしまう。この状態をキャッシュコヒーレンス(cache coherence)と呼ぶ。
コヒーレンスという単語自体の意味は、”干渉のしやすさ”を表していて、音響や光学系の分野で使われている言葉らしい。
不整合が発生する状態を例を挙げて説明すると、以下のようになる
動作 メモリの値 CPU1のキャッシュ CPU2のキャッシュ step0 初期状態 0 step1 CPU1がメモリをread 0 0 step2 CPU2がメモリをread 0 0 0 step3 CPU1がメモリに1をwrite 0 1 0 -> step4で、CPU1,2間のキャッシュ値に差異が発生!! |
ここで、記憶システムに”コヒーレンスが無い”という意味を,もう少し厳密に定義してみる。
“コヒーレンスが無い”記憶システムというのは、以下のことが出来る事を意味する。
読み出し値の保証 step3の後で、CPU1がメモリをreadしたら1が返ってくる -> 当たり前の話 キャッシュ値の反映 step3の後で、CPU2がメモリをreadしたら1が返ってくる -> CPU1のキャッシュをCPU2のキャッシュに 反映させる仕組みが必要 メモリアクセスのシリアライズ 複数のCPUが同一アドレスのメモリに、同時に書き込みを行えないようになっている -> 上記例には若干うそが合って、両CPUは同時に動作している。 step3でCPU1,CPU2が同時に異なる値をメモリに書き込むと問題が出るので、 そのようなアクセスは同期をとってシリアライズする必要がある。 |
上記のことを満たせないと、”コヒーレンスがある”記憶システムになる訳で、シングルCPU環境の構成を単純にマルチプロセッサ化すると、前述の例のようにコヒーレンスがある形になってしまう。
上記の問題を解消するためには、各プロセッサ間でやり取りをする仕組みが必要で、この仕組みをキャッシュコヒーレンスプロトコルと呼ぶ。
キャッシュコヒーレンスプロトコルは、バススヌープ方式が一般的で、他にスナーフィングや、ディレクトリベースの一貫性機構などがある。
バススヌープというのは、個々のCPU(というかキャッシュコントローラー)が、常にアドレスバスを監視していて、自分がキャッシュしているデータを他のCPUが書き換えたら自分のキャッシュを無効化するという考え方。
これの実装として、ライトイインバリデートプロトコル(write invalidate protocol)というものがある。
ライトイインバリデートプロトコルの仕組み
前述したように、コヒーレンスが無い状態にする簡単な方法は、ライトキャッシュを1CPUだけが排他的に独占できればよい。ライトイインバリデートプロトコルについてざっくりとしたコンセプトを説明すると、以下の4つになる。
あるメモリブロックのリードキャッシュは、複数のCPUが保持する事が可能。 あるメモリブロックのライトキャッシュは、単一のCPUしか保持できない。 システムとして、どのCPUがライトキャッシュを保持しているか、オーナーを管理している。 ライトキャッシュされたデータを他のCPUが要求した時は、メモリに変わって保有者が返事する。 |
これを踏まえて、前述のシーケンスでのデータアクセスを再現してみる。
動作 メモリ値 CPU1 CPU2 cache cache step0 初期状態 0 step1 CPU1がメモリをread 0 0 step2 CPU2がメモリをread 0 0 0 step3 CPU1がメモリにwrite 0 1 -> キャッシュを無効化 step4 CPU2がメモリをread 1 1 1 -> CPU1の値がメモリに書き込まれ、 同時にCPU2はそれをキャッシュする |
5.9 高度な話題:キャッシュ・コントローラの実現(◎CDコンテンツ)
CDがないので省略
5.10 実例:AMD Opteron X4 (Barcelona)とIntel Nehalemの記憶階層
特筆すべき事が無かったので、省略
5.11 誤信と落とし穴
落とし穴:キャッシュをシミュレーションする際に、バイトアドレッシングやキャッシュのブロックサイズを計算に入れるのを忘れる事
サイズやオフセットを計算する時に、単位がバイトだったら8bit単位だけど、ワードだと32bit単位とかになるので、勘違いに注意。
落とし穴:プログラムを組んだりコンパイラでコード生成を行う際に、記憶システムの動作を無視する事
例えば以下の処理は、メモリの離れた位置をアクセスしていくので、キャッシュの恩恵にあずかれないリスクがある。
int a[10][10]; int sum = 0; for ( int loop1 = 0; loop1 < 10; loop1++ ) { for ( int loop2 = 0; loop2 < 10; loop2++ ) { sum += a[loop2][loop1]; } } |
これを、”sum += a[loop1][loop2];”にすれば、連続領域を順にスキャンするので、キャッシュが効きやすい。
落とし穴:共有キャッシュの場合に、そのキャッシュを共有しているコアまたはスレッドの数よりも、セットアソシエイティブ方式の連想度を小さくする事。
例えば4CPU構成の時は、セットアソシエイティブの連想度は4ウェイ以上にする必要があるらしい。
なぜなのかは読んでも、意味が分からなかった…
落とし穴:アウトオブオーダー方式のプロセッサの記憶階層を評価するのに、平均メモリアクセス時間を使用すること
アウトオブオーダーで実行できる場合は、キャッシュミスが発生しても、その間他の命令を実行できる可能性があるので、簡単には計算できない
落とし穴:それまでセグメント化されていなかったアドレス空間の上にセグメントを追加する事によって、アドレス空間を拡張する事。
大きな配列がセグメントをまたぐ時、そのアクセスが煩雑になったりするので結構面倒になる。的な感じ。
落とし穴:仮想化できるように設計されていない命令セットアーキテクチャ上で、仮想マシンモニタを実現する事
CPUのサポートが無いと、ゲストVMからレジスタ内の制御用情報を任意に書き換えられてしまうので、実装が難しくなる。ハードのサポートが得られない場合,ホスト側に一部手を入れる場合もある(例:Xen VMM)。
5.12 おわりに
省略5.13 歴史展望と参考文献(◎CDコンテンツ)
CDがないので省略5.14 演習問題
省略
関連記事
コメントを残す