KVM の halt polling システム

KVM の halt polling システムは、KVM 内の機能であり、ゲストが cede によって実行を やめることを選んだ後、ホスト内で一定時間ポーリングすることで、状況によっては ゲストのレイテンシを削減できる。つまり、ゲストの vCPU が cede したとき、または PowerPC の場合は 1 つの vcore のすべての vCPU が cede したとき、ホストカーネルは、 他の何かを実行させるために CPU をスケジューラに明け渡す前に、起床条件をポーリングする。

ポーリングは、ゲストをすぐに再実行できる場合にレイテンシ上の利点をもたらす。 少なくともスケジューラを通る往復を節約でき、通常は数マイクロ秒程度である。 ただし、性能上の利点はワークロードに依存する。ポーリング間隔中に起床ソースが 到着しない場合、または実行キュー上の他のタスクが実行可能な場合、スケジューラが 呼び出される。したがって、halt polling は、起床期間が非常に短く、halt polling に 費やす時間が最小化され、スケジューラを呼び出さないことによる時間節約が識別できる ワークロードで特に有用である。

汎用的な halt polling コードは次で実装されている:

virt/kvm/kvm_main.c: kvm_vcpu_block()

PowerPC の kvm-hv 固有のケースは次で実装されている:

arch/powerpc/kvm/book3s_hv.c: kvmppc_vcore_blocked()

Halt Polling 間隔

スケジューラを呼び出す前にポーリングする最大時間は、halt polling 間隔と呼ばれ、 無意味なポーリングを制限する試みとして、ポーリングの有効性の認識に基づいて増減される。 この値は、vCPU 構造体の次のいずれかに格納される:

kvm_vcpu->halt_poll_ns

または PowerPC の kvm-hv の場合は、vcore 構造体に格納される:

kvmppc_vcore->halt_poll_ns

したがって、これは vCPU ごと (または vcore ごと) の値である。

ポーリング中に halt polling 間隔内で起床ソースを受信した場合、間隔は変更されない。 ポーリング間隔中に起床ソースを受信しなかった場合 (したがってスケジューラが呼び出される)、 2 つの選択肢がある。ポーリング間隔と合計ブロック時間[0] がグローバル最大ポーリング間隔 (下記のモジュールパラメータを参照) より短かったか、合計ブロック時間がグローバル最大 ポーリング間隔より長かったかである。

ポーリング間隔と合計ブロック時間の両方がグローバル最大ポーリング間隔より短かった場合、 ポーリング間隔を増やすことができる。次回、より長いポーリング間隔の間にホストが ポーリングしているときに起床ソースを受信し、レイテンシ上の利点を得られることを 期待してのことである。ポーリング間隔は grow_halt_poll_ns() 関数で増加され、 モジュールパラメータ halt_poll_ns_grow と halt_poll_ns_grow_start によって乗算される。

合計ブロック時間がグローバル最大ポーリング間隔より長かった場合、ホストは (グローバル最大値によって制限されるため) ポーリング間隔中に起床するのに十分な長さを 決してポーリングしない。したがって、無意味なポーリングを避けるために間隔を縮小してもよい。 ポーリング間隔は shrink_halt_poll_ns() 関数で縮小され、モジュールパラメータ halt_poll_ns_shrink で除算される。halt_poll_ns_shrink == 0 の場合に限り 0 に設定される。

この調整プロセスは、ある定常状態のポーリング間隔に近づこうとするが、実際にうまく 機能するのは、ほぼ一定の割合で発生する起床の場合だけである。そうでなければ、 ポーリング間隔は絶えず調整されることになる。

[0] 合計ブロック時間:

halt polling 関数が呼び出されてから起床ソースを受信するまでの時間 (その関数内でスケジューラが呼び出されるかどうかに関係ない)。

モジュールパラメータ

kvm モジュールには 4 つの調整可能なモジュールパラメータがあり、グローバル最大 ポーリング間隔、初期値 (0 から増加させる)、およびポーリング間隔を増減させる割合を 調整する。これらの変数は include/linux/kvm_host.h で定義され、 virt/kvm/kvm_main.c のモジュールパラメータ、または PowerPC の kvm-hv の場合は arch/powerpc/kvm/book3s_hv.c のモジュールパラメータとして定義されている。

モジュールパラメータ

説明

デフォルト値

halt_poll_ns

各 vCPU のポーリング間隔の上限値を定義する、グローバル最大ポーリング間隔。

KVM_HALT_POLL_NS_DEFAULT (アーキテクチャごとの値)

halt_poll_ns_grow

grow_halt_poll_ns() 関数で halt polling 間隔に乗算される値。

2

halt_poll_ns_grow_start

grow_halt_poll_ns() 関数でゼロから増加させる初期値。

10000

halt_poll_ns_shrink

shrink_halt_poll_ns() 関数で halt polling 間隔を除算する値。

2

これらのモジュールパラメータは、次の sysfs ファイルから設定できる:

/sys/module/kvm/parameters/

備考: これらのモジュールパラメータはシステム全体の値であり、VM ごとに調整することは

できない。

これらのパラメータへの変更は、次に halt するときに新しい vCPU と既存の vCPU によって 反映される。ただし、KVM_CAP_HALT_POLL を使用する VM は例外である (次の節を参照)。

KVM_CAP_HALT_POLL

KVM_CAP_HALT_POLL は、ユーザ空間が VM ごとに halt_poll_ns を上書きできるようにする VM ケイパビリティである。KVM_CAP_HALT_POLL を使用する VM は halt_poll_ns を完全に 無視する (ただし、halt_poll_ns_grow、halt_poll_ns_grow_start、halt_poll_ns_shrink には従う)。

このケイパビリティについて詳しくは、Documentation/virt/kvm/api.rst を参照。

補足

  • halt_poll_ns モジュールパラメータを設定するときは注意が必要である。大きな値は、 そうでなければほぼ完全にアイドル状態になるマシンで、CPU 使用率を 100% に押し上げる 可能性がある。これは、ゲストに、ごくわずかな作業しか行われず、かつ間隔がかなり離れた 起床がある場合でも、その周期がグローバル最大ポーリング間隔 (halt_poll_ns) より短ければ、 ホストは常にブロック時間全体をポーリングし、CPU 使用率が 100% になるためである。

  • halt polling は本質的に、電力使用量とレイテンシの間のトレードオフを提示する。 モジュールパラメータは、このトレードオフの傾向を調整するために使うべきである。 アイドル CPU 時間は本質的に、ゲストに入るときのレイテンシを減らす目的で、 ホストカーネル時間に変換される。

  • halt polling は、その CPU 上で実行可能な他のタスクがない場合にのみホストによって 行われる。そうでなければ、ポーリングは直ちに停止し、他のタスクを実行できるように スケジューラが呼び出される。したがって、ゲストが CPU のサービス拒否を引き起こすことは できない。