KVM 暫停輪詢系統¶
KVM 暫停輪詢系統在 KVM 內部提供了一項功能,該功能在某些情況下可以透過在宿主機中進行一段時間的輪詢來減少客戶機的延遲,即在客戶機選擇透過讓出(cedeing)不再執行時進行輪詢。也就是說,當客戶機 vcpu 讓出,或者在 powerpc 的情況下,當單個 vcore 的所有 vcpu 都讓出時,宿主機核心會在將 CPU 讓給排程器以執行其他任務之前,輪詢喚醒條件。
輪詢在客戶機可以非常快速地再次執行的情況下提供了延遲優勢,至少可以節省一次透過排程器的行程,通常大約在幾微秒的量級,儘管效能收益取決於工作負載。如果在輪詢間隔內沒有喚醒源到達,或者執行佇列中的其他任務可執行,則會呼叫排程器。因此,暫停輪詢對於喚醒週期非常短的工作負載特別有用,在這種工作負載中,暫停輪詢所花費的時間最小化,並且不呼叫排程器所節省的時間是顯而易見的。
通用的暫停輪詢程式碼實現在
virt/kvm/kvm_main.c: kvm_vcpu_block()
powerpc kvm-hv 特定案例實現在
arch/powerpc/kvm/book3s_hv.c: kvmppc_vcore_blocked()
暫停輪詢間隔¶
在呼叫排程器之前進行輪詢的最長時間,稱為暫停輪詢間隔,會根據輪詢的感知效果進行增加和減少,以試圖限制無意義的輪詢。此值儲存在 vcpu 結構體中
kvm_vcpu->halt_poll_ns
或在 powerpc kvm-hv 的情況下,儲存在 vcore 結構體中
kvmppc_vcore->halt_poll_ns
因此,這是一個每個 vcpu(或 vcore)的值。
在輪詢期間,如果在暫停輪詢間隔內收到喚醒源,則間隔保持不變。如果在輪詢間隔內未收到喚醒源(因此呼叫了排程器),則有兩種情況:要麼輪詢間隔和總阻塞時間[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] 總阻塞時間
從呼叫暫停輪詢函式到收到喚醒源之間的時間(無論是否在該函式內呼叫排程器)。
模組引數¶
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()` 函式中,暫停輪詢間隔所乘的值。 |
2 |
halt_poll_ns_grow_start |
在 `grow_halt_poll_ns()` 函式中,從零開始增長的初始值。 |
10000 |
halt_poll_ns_shrink |
在 `shrink_halt_poll_ns()` 函式中,暫停輪詢間隔所除的值。 |
2 |
這些模組引數可以從以下 sysfs 檔案中設定:
/sys/module/kvm/parameters/
- 注意:這些模組引數是系統範圍的值,無法
按每個虛擬機器進行調整。
對這些引數的任何更改都將在新的和現有的 vCPU 下次暫停時生效,但使用 `KVM_CAP_HALT_POLL` 的虛擬機器除外(參見下一節)。
KVM_CAP_HALT_POLL¶
`KVM_CAP_HALT_POLL` 是一種虛擬機器能力,允許使用者空間按每個虛擬機器覆蓋 `halt_poll_ns`。使用 `KVM_CAP_HALT_POLL` 的虛擬機器完全忽略 `halt_poll_ns`(但仍遵循 `halt_poll_ns_grow`、`halt_poll_ns_grow_start` 和 `halt_poll_ns_shrink`)。
有關此能力的更多資訊,請參閱KVM(基於核心的虛擬機器)API 權威文件。
進一步說明¶
設定 `halt_poll_ns` 模組引數時應謹慎,因為一個大值有可能在否則幾乎完全空閒的機器上將 CPU 使用率推高到 100%。這是因為即使客戶機有喚醒,但在這期間完成的工作很少且喚醒間隔很遠,如果週期短於全域性最大輪詢間隔(`halt_poll_ns`),那麼宿主機將始終在整個阻塞時間內進行輪詢,從而導致 CPU 利用率達到 100%。
暫停輪詢本質上是在功耗和延遲之間做出權衡,應使用模組引數來調整此偏好。空閒 CPU 時間基本上被轉換為宿主機核心時間,目的是在進入客戶機時降低延遲。
暫停輪詢只會在該 CPU 上沒有其他可執行任務時由宿主機執行,否則輪詢將立即停止,並呼叫排程器以允許其他任務執行。因此,這不允許客戶機導致 CPU 的拒絕服務。