摘要:阿里提出里面提供機制,即在退出前先等會兒,這樣可以減少退出次數。優點性能較阿里好缺點只適用于獨占物理核場景狀態社區討論中,比較大可能被接受。針對不同的業務模型,采用不同的機制最大化業務性能。
本文由作者朱益軍授權網易云社區發布。
簡介
在實際業務中,guest執行HLT指令是導致虛擬化overhead的一個重要原因。如[1].
KVM halt polling特性就是為了解決這一個問題被引入的,它在Linux 4.3-rc1被合入主干內核,其基本原理是當guest idle發生vm-exit時,host 繼續polling一段時間,用于減少guest的業務時延。進一步講,在vcpu進入idle之后,guest內核默認處理是執行HLT指令,就會發生vm-exit,host kernel并不馬上讓出物理核給調度器,而是poll一段時間,若guest在這段時間內被喚醒,便可以馬上調度回該vcpu線程繼續運行。
polling機制帶來時延上的降低,至少是一個線程調度周期,通常是幾微妙,但最終的性能提升是跟guest內業務模型相關的。如果在host kernel polling期間,沒有喚醒事件發生或是運行隊列里面其他任務變成runnable狀態,那么調度器就會被喚醒去干其他任務的事。因此,halt polling機制對于那些在很短時間間隔就會被喚醒一次的業務特別有效。
代碼流程
guest執行HLT指令發生vm-exit后,kvm處理該異常,在kvm_emulate_halt處理最后調用kvm_vcpu_halt(vcpu)。
int kvm_vcpu_halt(struct kvm_vcpu *vcpu){
++vcpu->stat.halt_exits; if (lapic_in_kernel(vcpu)) { vcpu->arch.mp_state = KVM_MP_STATE_HALTED; return 1; } else { vcpu->run->exit_reason = KVM_EXIT_HLT; return 0; }
}
將mp_state的值置為KVM_MP_STATE_HALTED,并返回1。
static int vcpu_run(struct kvm_vcpu vcpu){ int r; struct kvm kvm = vcpu->kvm;
vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); for (;;) { if (kvm_vcpu_running(vcpu)) { r = vcpu_enter_guest(vcpu); } else { r = vcpu_block(kvm, vcpu); } if (r <= 0) break; //省略 }
}
由于kvm處理完halt異常后返回1,故主循環不退出,但在下一個循環時kvm_vcpu_running(vcpu)返回false,所以進入vcpu_block()分支,隨機調用kvm_vcpu_block()。
通用的halt polling代碼在virt/kvm/kvm_main.c文件中的額kvm_vcpu_block()函數中實現。
ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns);do { /*
* This sets KVM_REQ_UNHALT if an interrupt * arrives. */ if (kvm_vcpu_check_block(vcpu) < 0) { ++vcpu->stat.halt_successful_poll; if (!vcpu_valid_wakeup(vcpu)) ++vcpu->stat.halt_poll_invalid; goto out; } cur = ktime_get();
} while (single_task_running() && ktime_before(cur, stop));
情況一:如果當前物理核上沒有其他task處于running狀態,而且在polling時間間隔內,那么就一直等著,直到kvm_vcpu_check_block(vcpu) < 0,即vcpu等待的中斷到達,便跳出循環。
out:
block_ns = ktime_to_ns(cur) - ktime_to_ns(start); if (!vcpu_valid_wakeup(vcpu)) shrink_halt_poll_ns(vcpu); else if (halt_poll_ns) { if (block_ns <= vcpu->halt_poll_ns) ; /* we had a long block, shrink polling */ else if (vcpu->halt_poll_ns && block_ns > halt_poll_ns) shrink_halt_poll_ns(vcpu); /* we had a short halt and our poll time is too small */ else if (vcpu->halt_poll_ns < halt_poll_ns && block_ns < halt_poll_ns) grow_halt_poll_ns(vcpu); } else vcpu->halt_poll_ns = 0; trace_kvm_vcpu_wakeup(block_ns, waited, vcpu_valid_wakeup(vcpu)); kvm_arch_vcpu_block_finish(vcpu);
這段代碼主要用于調整下一次polling的等待時間。若block_ns大于halt_poll_ns,即vcpu halt時間很短就被喚醒了,則把下一次的halt_poll_ns調長;否則,減短。
情況二:如果當前物理核上其他task變成running態,或polling時間到期,則喚醒調度器,調度其他任務,如下代碼。
for (;;) {
prepare_to_swait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); if (kvm_vcpu_check_block(vcpu) < 0) break; waited = true; schedule(); }
模塊參數說明
Module Parameter Description default Value
halt_poll_ns The global max polling interval which defines the ceiling value which defines the ceiling value which defines the ceiling value of the polling interval for each vcpu. KVM_HALT_POLL_NS_DEFAULT (per arch value)
halt_poll_ns_grow The value by which the halt polling interval is multiplied polling interval is multiplied polling interval is multiplied in the grow_halt_poll_ns() function. 2
halt_poll_ns_shrink The value by which the halt polling interval is divided in the shrink_halt_poll_ns() function. 0
kvm用這3個參數來動態調整最大halt polling時長。debugfs下/sys/module/kvm/parameters/存放著這3個模塊參數的默認值。X86架構下,KVM_HALT_POLL_NS_DEFAULT默認值為400000。 grow一次,值乘以halt_poll_ns_grow:
static void grow_halt_poll_ns(struct kvm_vcpu *vcpu){
unsigned int old, val, grow; old = val = vcpu->halt_poll_ns; grow = READ_ONCE(halt_poll_ns_grow); /* 10us base */ if (val == 0 && grow) val = 10000; else val *= grow; if (val > halt_poll_ns) val = halt_poll_ns; vcpu->halt_poll_ns = val; trace_kvm_halt_poll_ns_grow(vcpu->vcpu_id, val, old);
}
shrink一次,值除以halt_poll_ns_shrink,當前系統該參數為0,說明在設定的polling時長下虛擬機未被喚醒,那么下一次polling時長降到基準值10us:
static void shrink_halt_poll_ns(struct kvm_vcpu *vcpu){
unsigned int old, val, shrink; old = val = vcpu->halt_poll_ns; shrink = READ_ONCE(halt_poll_ns_shrink); if (shrink == 0) val = 0; else val /= shrink; vcpu->halt_poll_ns = val; trace_kvm_halt_poll_ns_shrink(vcpu->vcpu_id, val, old);
}
值得注意幾點
該機制有可能導致物理CPU實際空閑的情況下占用率表現為100%。因為如果guest上業務模型是隔一段時間被喚醒一次來處理很少量的流量,并且這個時間間隔比kvm halt_poll_ns短,那么host將poll整個虛擬機的block時間,cpu占用率也會沖上100%。
halt polling是電源能耗和業務時延的一個權衡。為了減少進入guest的時延,idle cpu時間轉換為host kernel時間。
該機制只有在CPU上沒有其他running任務的情況得以應用,不然polling動作被立馬終止,喚醒調度器,調度其他進程。
延伸閱讀
業界針對虛擬機idle這個課題有比較多的研究,因為它帶來了比較大的overhead。主要可以歸結為以下幾種:
idle=poll,即把虛擬機idle時一直polling,空轉,不退出。這樣不利于物理CPU超線程的發揮。
阿里提出guest里面提供halt polling機制,即在VM退出前先等會兒,這樣可以減少VM退出次數。 --- 優點:性能較社區halt polling機制好;缺點:需要修改guest內核;狀態:社區尚未接收 https://lwn.net/Articles/732236/
AWS及騰訊考慮guest HLT指令不退出。 --- 優點:性能較阿里好;缺點:只適用于vcpu獨占物理核場景;狀態:社區討論中,比較大可能被接受。https://patchwork.kernel.org/...
idle等于mwait及mwait不退出。 --- 需要高版本kvm及高版本guest內核支持。
總結
如何高效地處理虛擬機idle是提升虛擬化性能的研究點。針對不同的業務模型,采用不同的機制最大化業務性能。后續將在考拉及其他業務上逐個驗證這些方案。
參考文檔
https://www.linux-kvm.org/ima...
http://events17.linuxfoundati...
http://events17.linuxfoundati...
https://www.kernel.org/doc/Do...
免費領取驗證碼、內容安全、短信發送、直播點播體驗包及云服務器等套餐
更多網易技術、產品、運營經驗分享請訪問網易云社區。
文章來源: 網易云社區
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/25360.html
摘要:和的云計算功能特點對比正式這個戰爭或者說趨勢的一個生動寫照。總而言之,目前調度器將只會對部署虛擬機環節有影響。目前有一個孵化項目其作用是為提供虛擬機級別高可用支持。容錯在中沒有針對于容錯的功能,并且截至目前也沒有計劃去完成這些功能。 OpenStack中國社區編者按:在云計算生態系統中,有兩種類型的用戶需要使用云計算資源:傳統型(Traditional IT applications)和在互...
摘要:分析惡意軟件有很多方法。這是一個虛擬化環境下的惡意軟件分析系統。整體上,基于虛擬機技術,使用中央控制系統和模塊設計,結合的自動化特征,已經是頗為自動化的惡意軟件行為研究環境。加密的通訊幾乎不可能直接分析。 分析惡意軟件(malicious ware)有很多方法。請容我不自量力推薦兩個開放源代碼的免費系統 Cuckoo 和 MalWasm 。這是一個虛擬化環境下的惡意軟件分析系統。 基...
閱讀 3677·2021-09-22 15:34
閱讀 1186·2019-08-29 17:25
閱讀 3399·2019-08-29 11:18
閱讀 1371·2019-08-26 17:15
閱讀 1740·2019-08-23 17:19
閱讀 1228·2019-08-23 16:15
閱讀 718·2019-08-23 16:02
閱讀 1335·2019-08-23 15:19