X86 ベースアーキテクチャのタイムキーピング仮想化
- Author:
Zachary Amsden <zamsden@redhat.com>
- Copyright:
2010, Red Hat. All rights reserved.
1. 概要
X86 プラットフォーム、とりわけこのプラットフォームの仮想化で最も複雑な部分の 1 つ は、利用できるタイミングデバイスが膨大であることと、それらデバイスのエミュレーシ ョンが複雑であることだ。さらに、時間の仮想化は新たな難題をもたらす。ゲスト CPU の 制御が及ばないところで、時間が多重化されて分割されるためだ。
まず利用できる各種のタイムキーピングハードウェアを説明し、次に生じる問題と利用で きる解決策を挙げ、特定のクラスの KVM ゲストに対する具体的な推奨を示す。
この文書の目的は、他所では見つけにくいタイムキーピング関連のデータと情報、とくに KVM とハードウェアベースの仮想化に関連する情報を集めることである。
2. タイミングデバイス
まず利用できる基本的なハードウェアデバイスを論じる。TSC とそれに関連する KVM クロ ックは特別であり、詳しい説明が必要なので、次の節で述べる。
2.1. i8254 - PIT
最初期に利用できたタイマーデバイスの 1 つが、プログラマブル割り込みタイマー(PIT) である。PIT は 1.193182 MHz の固定周波数のベースクロックと、周期的または単発の割 り込みを発生するようプログラムできる 3 つのチャネルを持つ。これら 3 つのチャネル は異なるモードに設定でき、それぞれに独立したカウンタを持つ。チャネル 1 と 2 は元 の IBM PC では汎用には使えず、歴史的には RAM リフレッシュと PC スピーカーの制御に つながれていた。現在では PIT は通常、エミュレートされたチップセットの一部として統 合されており、独立した物理 PIT は使われない。
PIT は I/O ポート 0x40 - 0x43 を使う。16 ビットカウンタへのアクセスは、I/O ポート に対する 1 バイトまたは複数バイトのアクセスで行う。6 つのモードがあるが、すべての モードがすべてのタイマーで使えるわけではない。モード 1 と 5 に必要なゲート入力が接 続されているのはタイマー 2 だけだからだ。ゲート線はポート 61h のビット 0 で制御さ れる。次の図のとおりである:
-------------- ----------------
| | | |
| 1.1932 MHz|---------->| CLOCK OUT | ---------> IRQ 0
| Clock | | | |
-------------- | +->| GATE TIMER 0 |
| ----------------
|
| ----------------
| | |
|------>| CLOCK OUT | ---------> 66.3 KHZ DRAM
| | | (aka /dev/null)
| +->| GATE TIMER 1 |
| ----------------
|
| ----------------
| | |
|------>| CLOCK OUT | ---------> Port 61h, bit 5
| | |
Port 61h, bit 0 -------->| GATE TIMER 2 | \_.---- ____
---------------- _| )--|LPF|---Speaker
/ *---- \___/
Port 61h, bit 1 ---------------------------------/
次にタイマーモードを述べる。
- モード 0: 単発タイムアウト。
ゲートがハイのとき(タイマー 0 と 1 では常にハイ)にカウントダウンする、ソフトウ ェアによる単発のタイムアウトである。カウントがゼロに達すると、出力がハイになる。
- モード 1: トリガされる単発。
出力は最初はハイに設定される。ゲート線がハイになるとカウントダウンが始まり(ゲート がローになっても止まらない)、その間は出力がローに設定される。カウントがゼロに達 すると、出力がハイになる。
- モード 2: レートジェネレータ。
出力は最初はハイに設定される。カウントダウンが 1 に達すると、出力は 1 カウント分 だけローになり、その後ハイに戻る。値は再ロードされ、カウントダウンは自動的に再開 する。ゲート線がローになると、カウントは停止する。ゲートをローにしたときに出力が ローなら、出力は自動的にハイになる(これはタイマー 2 だけに影響する)。
- モード 3: 方形波。
ハイ / ローの方形波を生成する。カウントはパルスの長さを決め、ゼロに達するとハイと ローが入れ替わる。カウントはゲートがハイのときだけ進み、ゼロに達すると自動的に再 ロードされる。カウントは各クロックで 2 回デクリメントされ、本来の周期レートで完 全なハイ / ローの周期を生成する。カウントが偶数なら、クロックは N/2 カウント分ハ イ、N/2 カウント分ローになる。カウントが奇数なら、クロックは (N+1)/2 カウント分 ハイ、(N-1)/2 カウント分ローになる。カウンタがラッチするのは偶数値だけなので、読 み出しでは奇数値は観測されない。これがタイマー 2 に意図されたモードであり、方形波 出力をローパスフィルタして正弦波に似た音を生成する。
- モード 4: ソフトウェアストローブ。
このモードをプログラムしてカウンタをロードしたあと、出力はカウンタがゼロに達する までハイのままである。次に出力は 1 クロックサイクル分だけローになり、ハイに戻る。 カウンタは再ロードされない。カウントはゲートがハイのときだけ行われる。
- モード 5: ハードウェアストローブ。
カウンタをプログラムしてロードしたあと、出力はハイのままである。ゲートが上げられ るとカウントダウンが始まり(ゲートがローになっても止まらない)、カウンタがゼロに 達すると、出力は 1 クロックサイクル分だけローになり、その後ハイに戻る。カウンタは 再ロードされない。
通常のバイナリカウントに加えて、PIT は BCD カウントをサポートする。コマンドポート 0x43 を使って、3 つのタイマーそれぞれのカウンタとモードを設定する。
ポート 0x43 に発行する PIT コマンドは、次のビットエンコーディングを使う:
Bit 7-4: Command (See table below)
Bit 3-1: Mode (000 = Mode 0, 101 = Mode 5, 11X = undefined)
Bit 0 : Binary (0) / BCD (1)
Command table:
0000 - Latch Timer 0 count for port 0x40
sample and hold the count to be read in port 0x40;
additional commands ignored until counter is read;
mode bits ignored.
0001 - Set Timer 0 LSB mode for port 0x40
set timer to read LSB only and force MSB to zero;
mode bits set timer mode
0010 - Set Timer 0 MSB mode for port 0x40
set timer to read MSB only and force LSB to zero;
mode bits set timer mode
0011 - Set Timer 0 16-bit mode for port 0x40
set timer to read / write LSB first, then MSB;
mode bits set timer mode
0100 - Latch Timer 1 count for port 0x41 - as described above
0101 - Set Timer 1 LSB mode for port 0x41 - as described above
0110 - Set Timer 1 MSB mode for port 0x41 - as described above
0111 - Set Timer 1 16-bit mode for port 0x41 - as described above
1000 - Latch Timer 2 count for port 0x42 - as described above
1001 - Set Timer 2 LSB mode for port 0x42 - as described above
1010 - Set Timer 2 MSB mode for port 0x42 - as described above
1011 - Set Timer 2 16-bit mode for port 0x42 as described above
1101 - General counter latch
Latch combination of counters into corresponding ports
Bit 3 = Counter 2
Bit 2 = Counter 1
Bit 1 = Counter 0
Bit 0 = Unused
1110 - Latch timer status
Latch combination of counter mode into corresponding ports
Bit 3 = Counter 2
Bit 2 = Counter 1
Bit 1 = Counter 0
The output of ports 0x40-0x42 following this command will be:
Bit 7 = Output pin
Bit 6 = Count loaded (0 if timer has expired)
Bit 5-4 = Read / Write mode
01 = MSB only
10 = LSB only
11 = LSB / MSB (16-bit)
Bit 3-1 = Mode
Bit 0 = Binary (0) / BCD mode (1)
2.2. RTC
元の PC で利用できた 2 つ目のデバイスは、MC146818 リアルタイムクロックである。元の デバイスは今では旧式であり、通常はシステムチップセットがエミュレートする。HPET や、 寄せ集めの IRQ ルーティングでエミュレートされることもある。
RTC は CMOS 変数を通してアクセスする。どのバイトを読み出すかはインデックスレジス タで制御する。インデックスレジスタは 1 つしかないため、CMOS の読み出しと RTC の読 み出しにはロックによる保護が要る(さらに、hwclock のようなユーザ空間ユーティリティ に RTC へ直接アクセスさせるのは危険である。カーネルの CMOS メモリの読み書きを壊す おそれがある)。
RTC は割り込みを生成し、通常は IRQ 8 にルーティングされる。この割り込みは周期的な タイマーとしても、1 日 1 回の追加アラームとしても機能し、MC146818 による CMOS レジ スタの更新が完了したあとに割り込みを発行することもできる。割り込みの種類は RTC の ステータスレジスタに示される。
RTC は、システムの電源が切れていてもバッテリー電源で現在時刻のフィールドを更新す る。ステータスレジスタに示されるとおり、更新の進行中は現在時刻のフィールドを読み出 すべきではない。
このクロックは 32.768kHz の水晶を使うので、RTC で秒を数えるならレジスタ A のビット 6-4 を 32kHz の分周にプログラムすべきである。
次は、もともと RTC/CMOS で使われていた RAM マップである:
Location Size Description
------------------------------------------
00h byte Current second (BCD)
01h byte Seconds alarm (BCD)
02h byte Current minute (BCD)
03h byte Minutes alarm (BCD)
04h byte Current hour (BCD)
05h byte Hours alarm (BCD)
06h byte Current day of week (BCD)
07h byte Current day of month (BCD)
08h byte Current month (BCD)
09h byte Current year (BCD)
0Ah byte Register A
bit 7 = Update in progress
bit 6-4 = Divider for clock
000 = 4.194 MHz
001 = 1.049 MHz
010 = 32 kHz
10X = test modes
110 = reset / disable
111 = reset / disable
bit 3-0 = Rate selection for periodic interrupt
000 = periodic timer disabled
001 = 3.90625 uS
010 = 7.8125 uS
011 = .122070 mS
100 = .244141 mS
...
1101 = 125 mS
1110 = 250 mS
1111 = 500 mS
0Bh byte Register B
bit 7 = Run (0) / Halt (1)
bit 6 = Periodic interrupt enable
bit 5 = Alarm interrupt enable
bit 4 = Update-ended interrupt enable
bit 3 = Square wave interrupt enable
bit 2 = BCD calendar (0) / Binary (1)
bit 1 = 12-hour mode (0) / 24-hour mode (1)
bit 0 = 0 (DST off) / 1 (DST enabled)
OCh byte Register C (read only)
bit 7 = interrupt request flag (IRQF)
bit 6 = periodic interrupt flag (PF)
bit 5 = alarm interrupt flag (AF)
bit 4 = update interrupt flag (UF)
bit 3-0 = reserved
ODh byte Register D (read only)
bit 7 = RTC has power
bit 6-0 = reserved
32h byte Current century BCD (*)
(*) location vendor specific and now determined from ACPI global tables
2.3. APIC
Pentium 以降のプロセッサでは、Advanced Programmable Interrupt Controller の一部と して、各 CPU がオンボードタイマーを利用できる。APIC はメモリマップドレジスタを通 してアクセスし、各 CPU に割り込みサービスを提供する。IPI とローカルタイマー割り込 みに使われる。
理論上は APIC はローカル割り込みの安全で安定した供給源だが、実際には、APIC という CPU ローカルのメモリマップドハードウェアの特殊な性質により、多くのバグや不具合が 起きてきた。CPU のエラッタが APIC の使用に影響し、回避策が必要になることがある点 に注意する。さらに、こうした回避策の一部は仮想化に独特の制約をもたらす。メモリマ ップド I/O の余分な読み出しによる追加のオーバーヘッドか、実装するのに計算コストが 高くなる追加機能のどちらかを要求するからだ。
APIC は Intel と AMD のマニュアルでよく文書化されているので、ここで詳細を繰り返 すことは避ける。APIC タイマーは LVT(local vector timer)レジスタでプログラムし、 単発または周期動作が可能で、バスクロックをプログラマブル分周レジスタで分周したも のに基づく、という点は指摘しておく。
2.4. HPET
HPET はかなり複雑で、もともとは X86 PC の PIT / RTC サポートを置き換えることを意 図していた。そうなるかどうかは今のところ不明である。PC ハードウェアのデファクトス タンダードは、これら古いデバイスをエミュレートすることだからだ。レガシーフリーと 称するシステムの中には、ハードウェアタイマーデバイスとして HPET だけをサポートす るものもある。
HPET の仕様はかなり緩くあいまいで、少なくとも 3 つのハードウェアタイマーを要求す るが、それより多くをサポートする実装の自由も認めている。また、タイマー周波数に固 定レートを課さないが、周波数・誤差・スルーについてはいくつかの極値を課す。
一般に HPET は、(PIT / RTC と比べて)高精度の時間源として推奨される。どのシステ ムにも HPET は 1 つしかないので、ローカルな変動に依存しない。HPET もメモリマップド であり、その存在は BIOS が ACPI テーブルを通して示す。
HPET の詳細な仕様は、ほかでもよく文書化されているので、この文書の現在の範囲を超え る。
2.5. オフボードタイマー
数多くのカードが、独自仕様のもの(ウォッチドッグボード)も一般的なもの(e1000)も、 カードに組み込まれた計時チップを持ち、そのレジスタがカーネルまたはユーザドライバ からアクセスできることがある。筆者の知る限り、これらを使って Linux などのカーネル のクロックソースを生成することはまだ試みられておらず、一般に、決められたルールに 従っていないとして快く思われていない。そうしたタイマーデバイスを正しく仮想化する には追加のサポートが必要であり、既知のオペレーティングシステムがこうしたことを行 っていないため、現時点では重要とはみなされていない。
3. TSC ハードウェア
TSC(time stamp counter)は理論上は比較的単純である。プロセッサが発行した命令サイ クルを数え、それを時間の尺度として使える。実際には、いくつもの問題があるため、使 うのが最も複雑なタイムキーピングデバイスである。
TSC は内部的には 64 ビットの MSR として表され、RDMSR、RDTSC、または RDTSCP(利用 できる場合)命令で読み出せる。以前は、ハードウェアの制約により TSC への書き込みが 可能だったが、一般に古いハードウェアでは 64 ビットカウンタの下位 32 ビットしか書 き込めず、カウンタの上位 32 ビットはクリアされた。しかし現在では、Intel プロセッ サのファミリ 0Fh のモデル 3、4、6、およびファミリ 06h のモデル e、f でこの制限が なくなり、64 ビットすべてが書き込み可能である。AMD のシステムでは、TSC MSR を書き 込む機能はアーキテクチャ上の保証ではない。
TSC は CPL-0 からアクセスでき、CPL > 0 のソフトウェアからは CR4.TSD ビットによっ て条件つきでアクセスできる。このビットを有効にすると、CPL > 0 からの TSC アクセス が無効になる。
一部のベンダは追加の命令 RDTSCP を実装している。これは TSC だけでなく、プロセッサ 番号に対応する指標もアトミックに返す。TSC が同期していない SMP システムで、TSC 変 数の配列を索引してオフセット情報を求めるのに使える。この命令の有無は CPUID の機能 ビットを調べて判断しなければならない。
VMX と SVM はどちらも、仮想化ハードウェアに拡張フィールドを用意し、ゲストから見え る TSC を定数でオフセットできるようにする。新しい実装では TSC をさらにスケーリン グできるようにするとされているが、このハードウェアはまだ広くは利用できない。
3.1. TSC の同期
ほとんどの実装で、TSC は CPU ローカルのクロックである。つまり SMP プラットフォー ムでは、CPU の電源投入のタイミングによって、異なる CPU の TSC が異なる時点から始 まることがある。一般に同じダイ上の CPU は同じクロックを共有するが、常にそうとは限 らない。
BIOS は電源投入の過程で TSC を再同期しようとすることがあり、オペレーティングシス テムや他のシステムソフトウェアも同様に試みることがある。いくつかのハードウェアの 制約が問題を悪化させる。TSC の 64 ビットすべてを書き込めない場合、後から到着した CPU の TSC をシステムの残りの TSC に一致させられず、TSC が同期しなくなる。これは BIOS やシステムソフトウェアが行うことがあるが、実際には、すべての値を同じクロック から読み出せない限り、完全に同期した TSC は得られない。それが可能なのは通常、シン グルソケットのシステムか、特別なハードウェアサポートを持つシステムだけである。
3.2. TSC と CPU ホットプラグ
すでに触れたように、システムの起動時刻より後に到着する CPU は、システムの残りと同 期した TSC 値を持たないことがある。システムソフトウェア、BIOS、SMM コードのいずれ かが、システムの残りに一致する値に TSC を設定しようとすることがあるが、完全な一致 は通常保証されない。このため、TSC が同期している状態から、TSC 同期の欠陥がどれほ ど小さくても OS と仮想化環境に露呈しうる状態へと、システムが戻ることがある。
3.3. TSC とマルチソケット / NUMA
マルチソケットのシステム、とくに大規模なマルチソケットシステムでは、単一の全体的 に分配されたクロックではなく、個々のクロックソースを持つ可能性が高い。これらのク ロックは異なる水晶で駆動されるため、周波数が完全には一致せず、温度や電気的な変動 によって CPU クロック、ひいては TSC が時間とともにドリフトする。正確なクロックと バスの設計によって、ドリフトが絶対誤差の中で固定されることもあれば、時間とともに 蓄積することもある。
さらに、非常に大規模なシステムでは、個々のコアのクロックを意図的にスルーさせるこ とがある。スペクトラム拡散クロッキングとして知られるこの手法は、クロック周波数と その高調波での EMI を低減する。通信機器とコンピュータ機器の FCC 規格を通すために 必要になることがある。
こうした理由から、NUMA やマルチソケットのシステムで TSC が同期したままであると信 用しないことが推奨される。
3.4. TSC と C ステート
C ステート、つまりプロセッサのアイドル状態、とくに C1E 以降のより深いスリープ状態 は、TSC にとっても問題になることがある。このような状態では TSC の進行が止まり、実 行を再開したときに他の CPU より遅れた TSC になることがある。そのような CPU は、 CPU とチップセットの識別情報に基づいてオペレーティングシステムが検出し、フラグを 立てなければならない。
そのような場合の TSC は、既知の外部クロックソースまで追いつかせることで補正でき る。
3.5. TSC の周波数変化 / P ステート
さらにややこしいことに、一部の CPU は周波数を変えることがある。そのとき TSC を同 じレートで動かすかどうかは CPU によって異なり、周波数の変化が段階的だったりスルー だったりするため、ある時点では TSC のレートは値の範囲に収まることしか分からないこ とがある。この場合、TSC は安定した時間源ではなく、使える時間源にするには、既知で 安定した外部クロックに対して較正しなければならない。
TSC が一定のレートで動くのか、P ステートに応じて変化するのかはモデル依存であり、 CPUID、チップセット、またはベンダ固有の MSR フィールドを調べて判断しなければなら ない。
さらに、一部のベンダには既知のバグがある。通常の動作中は P ステートが適切に補償さ れるが、プロセッサが非アクティブのとき、他のプロセッサからのキャッシュミスに応え るために P ステートが一時的に引き上げられることがある。このような場合、停止中の CPU の TSC が、停止していないプロセッサより速く進むことがある。AMD Turion プロセ ッサにこの問題があることが知られている。
3.6. TSC と STPCLK / T ステート
プロセッサに与えられる外部信号も TSC を停止させる効果を持つことがある。これは通常、 過熱状態を防ぐための熱緊急電力制御で行われ、通常、この状態が起きたことを検出する 方法はない。
3.7. TSC の仮想化 - VMX
VMX は RDTSC、RDMSR、WRMSR、RDTSCP 命令の条件つきトラップを提供し、これで任意の方 法での TSC の完全な仮想化に足りる。さらに VMX は、ホスト TSC に VMCS で指定した追 加の TSC_OFFSET フィールドを加えたものをパススルーできる。VMCS フィールドの読み書 きには特別な命令を使わなければならない。
3.8. TSC の仮想化 - SVM
SVM は RDTSC、RDMSR、WRMSR、RDTSCP 命令の条件つきトラップを提供し、これで任意の方 法での TSC の完全な仮想化に足りる。さらに SVM は、ホスト TSC に SVM コントロールブ ロックで指定した追加のオフセットフィールドを加えたものをパススルーできる。
3.9. Linux における TSC の機能ビット
まとめると、アーキテクチャによって明示的に保証されていない限り、TSC が完全に同期 したままであることを保証する方法はない。たとえ保証されていても、マルチソケットや NUMA のシステムの TSC は、ローカルには一貫していても独立に動作することがある。
次の機能ビットは Linux がさまざまな TSC の属性を示すために使うが、意味があるとみ なせるのは UP またはシングルノードのシステムだけである。
X86_FEATURE_TSC |
TSC がハードウェアで利用できる |
X86_FEATURE_RDTSCP |
RDTSCP 命令が利用できる |
X86_FEATURE_CONSTANT_TSC |
P ステートによって TSC のレートが変化しない |
X86_FEATURE_NONSTOP_TSC |
C ステートで TSC が停止しない |
X86_FEATURE_TSC_RELIABLE |
TSC 同期チェックをスキップする(VMware) |
4. 仮想化の問題
タイムキーピングは、仮想化ではとくに問題になる。いくつもの難題が生じるためだ。最 も明白な問題は、時間がホストと、場合によっては複数の仮想マシン(VM)の間で共有さ れることである。そのため仮想のオペレーティングシステムは、CPU を 100% 使って動作 しているわけではない。にもかかわらず、そう仮定していることが十分ありうる。割り込 み源が無効なときは厳密な範囲に収まっているはずだと期待するかもしれないが、実際に 無効なのはその仮想の割り込み源だけで、マシンはいつでもプリエンプトされうる。これ が問題を生むのは、実時間の経過、マシンの割り込みの注入、および関連するクロック源 が、もはや実時間と完全には同期しなくなるからである。
この同じ問題はネイティブのハードウェアでもある程度起こりうる。BIOS が SMM モード を使うとき、SMM モードが X86 システムで本来得られるはずのサイクルを奪うことがある ためだ。ただし、それほど極端な形ではない。しかし、SMM モードが仮想化と同様の問題 を引き起こしうるという事実は、こうした問題の多くをベアメタルで解決する十分な根拠 になる。
4.1. 割り込みによる計時
レガシーのオペレーティングシステムで起きる最も差し迫った問題の 1 つは、システムの タイムキーピングルーチンが、周期的な割り込みを数えて時間を追跡するよう設計されて いることが多い点である。これらの割り込みは PIT や RTC から来ることがあるが、問題 は同じである。ホストの仮想化エンジンが 1 秒あたり適切な数の割り込みを配信できない ことがあり、そのためゲストの時間が遅れる。これは、1000 HZ のような高い割り込みレ ートを選んだ場合にとくに問題になる。残念なことに、多くの Linux ゲストの既定がこれ である。
この問題を解決するには 3 つの方法がある。第一に、単に無視できることがある。「ウォ ールクロック」や「実時間」を追跡するための別の時間源を持つゲストは、正しい時間を 保つために割り込みを調整する必要がないことがある。これで足りない場合は、実効的な 割り込みレートを上げるために、ゲストに割り込みを追加で注入する必要があるかもしれ ない。この方法は、ホストの負荷やゲストの遅れが補償しきれないほど大きい極端な状況 で複雑になる。そこで別の解決策が生まれた。ゲストが失われたティックを認識し、内部 的に補償する必要があるかもしれないというものだ。理論上は有望だが、Linux でのこの 方針の実装はきわめて間違いやすく、失われたティックの補償には欠陥のある変種が、広 く使われている Linux システムにいくつも出回っている。
Windows は内部的に時間を保つ手段として周期的な RTC クロックを使うため、正しい時間 を保つには割り込みのスルーが必要である。ただし、十分に低いレート(編注: 18.2 Hz か?)を使っているため、実際にはまだ問題になっていない。
4.2. TSC のサンプリングと直列化
利用できる中で最も高精度な時間源として、CPU のサイクルカウンタは開発者の大きな関 心を集めてきた。前述のとおり、このタイマーには、ローカルで、不安定になりうる、同 期しない可能性がある源という性質に固有の多くの問題がある。TSC に固有ではないが、 その非常に正確な性質のために際立つ問題がサンプリング遅延である。定義上、カウンタ は一度読み出した時点で既に古い。しかし、カウンタが結果の実際の使用より先に読み出 されることもある。これは命令ストリームのスーパースカラ実行の結果であり、命令が順 不同で実行されることがある。このような実行を非直列化実行と呼ぶ。TSC で正確に測定 するには直列化した実行を強制する必要があり、CPUID や MSR の読み出しのような直列 化命令が要る。
CPUID は実際にはトラップアンドエミュレートの仕組みで仮想化されることがあるため、 この直列化はハードウェア仮想化の性能上の問題になりうる。そのため、正確なタイムス タンプカウンタの読み出しが常に得られるとは限らず、それ以外は完全に同期しているシ ステムでも、他の CPU から見た TSC の「後戻り」した読み出しに実装が備える必要があ るかもしれない。
4.3. timespec のエイリアシング
さらに、TSC に直列化がないことは、TSC の結果を別の時間源と比較して測るときに別の 難題をもたらす。TSC の精度がはるかに高いため、別のクロックがまだ同じ値を表してい る間に、TSC の多くの値が読み出されることがある。
つまり、外部クロック C が同じ値を保っている間に (T,T+10) を読むことがある。非直列 化の読み出しのため、実際には (T-1..T+10) のように変動する範囲になることがある。 したがって、TSC から計算しつつ外部の値に対して較正した時間は、有効な値の範囲を持 ちうる。この計算を較正し直すと、較正のあとに計算した時間が、較正の前に計算した時 間より後戻りすることがある。
この問題は、Linux の内部時間源であるカーネル時間でとくに顕著である。カーネル時間 は理論上は高分解能な timespec で表されるが、はるかに粗い粒度の間隔で進み、ときに jiffies のレートで、キャッチアップモードではさらに大きなステップで進むこともある。
このエイリアシングのため、kvmclock の計算と再較正、および TSC の計算から導かれる 他の値(TSC 仮想化自体など)には注意が必要である。
4.4. マイグレーション
仮想マシン(VM)のマイグレーションは、2 つの点でタイムキーピングに問題を引き起こ す。第一に、マイグレーション自体に時間がかかることがあり、その間は割り込みを配信 できず、そのあとにゲストの時間を追いつかせる必要があるかもしれない。必要なクロッ ク補正は通常、NTP で補正できる範囲に収まるほど小さいので、ここでは NTP がある程度 助けになる。
もう 1 つの懸念は、TSC(あるいは、生のバスクロックが露出している場合は HPET)に基 づくタイマーが異なるレートで動くようになり、ハイパーバイザがこれらを仮想化して何 らかの形で補償する必要があることである。さらに、より高速なマシンへのマイグレーシ ョンでは、パススルーした TSC を使えないことがある。通常より速く時間が進むおそれな しに、より高速なクロックをゲストに見せることはできないからだ。より低速なクロック は問題が小さく、元のレートまで常に追いつかせられる。KVM クロックは、TSC に対する 乗数とオフセットを単に保持し、ゲストがナノ秒分解能の値に変換し直すことで、こうし た問題を避ける。
4.5. スケジューリング
スケジューリングは正確なタイミングと割り込みの発火に基づくことがあるため、オペレ ーティングシステムのスケジューリングアルゴリズムは仮想化によって悪影響を受けるこ とがある。理論上、影響はランダムで広く一様に分布するはずだが、作為的ないし現実の シナリオ(ゲストのデバイスアクセス、仮想化エグジットの原因、起こりうるコンテキス トスイッチ)では、必ずしもそうとは限らない。この影響はよく研究されていない。
これを回避しようと、いくつかの実装は準仮想化されたスケジューラクロックを提供して いる。これは、仮想マシンが動作していた真の CPU 時間を示す。
4.6. ウォッチドッグ
ウォッチドッグタイマー、たとえば Linux のロック検出器は、ハードウェア仮想化の下で 動作していると、タイマー割り込みの遅延や実時間の経過の誤解釈により、誤って発火す ることがある。通常、これらの警告は誤りであり無視できるが、状況によってはそのよう な検出を無効にする必要がある。
4.7. 遅延と高精度のタイミング
仮想化されたシステムでは、正確なタイミングや遅延ができないことがある。これは、シ ステムが物理ハードウェアを制御している場合や、デバイスとの間の低速な I/O を補償す るために遅延を発行する場合に起こりうる。第一の問題は、仮想化されたシステムでは一 般に解決できない。ハードウェア制御ソフトウェアを適切に仮想化するには完全なリアル タイムオペレーティングシステムが必要であり、それにはリアルタイム対応の仮想化プラ ットフォームが要る。
第二の問題は性能上の問題を引き起こすことがあるが、重大な問題になる可能性は低い。 多くの場合、こうした遅延は設定または準仮想化によってなくせる。
4.8. 隠れチャネルと漏えい
上記の問題に加えて、仮想化された時間の完全な実装でない限り、時間の情報は必然的に ホストについてゲストへ漏れる。これにより、ゲストがハイパーバイザの存在を推測した り(レッドピル型の検出のように)、CPU 使用率そのものを信号チャネルとして使ってゲ スト間で情報を漏らしたりできることがある。こうした問題を防ぐには、実時間を追跡し なくなるかもしれない完全に分離された仮想時間が必要になる。これは特定のセキュリテ ィや QA の文脈では役立つことがあるが、一般に実運用の展開シナリオには推奨されない。