![](http://static.javashuo.com/static/loading.gif)
桔妹導讀:GPU虛擬機實例建立速度慢是公有云面臨的廣泛問題,因爲一般狀況下建立虛擬機屬於低頻操做而未引發業界的重視,實際生產中仍是存在對GPU實例建立時間有苛刻要求的業務場景。本文將介紹滴滴雲在解決該問題時的思路、方法、並展現最終的優化成果。html
從公有云服務商那裏購買過虛擬主機的資深用戶,通常會發現這麼個規律:建立一臺CPU虛擬主機是比較快的,可是要建立一臺包含GPU卡的虛擬主機一般須要等比較長的時間,整個建立過程短則數十秒鐘,長則數分鐘。對於絕大多少的用戶來講,虛擬主機的建立時間長一點對他們影響並不大,由於建立虛擬機屬於相對低頻操做。可是也會有一些特定的用戶因爲其業務場景交互性比較強,會對虛擬主機的建立時間有相對苛刻的要求,由於過長的建立時間會致使其業務用戶體驗不好。本文將從虛擬化的角度來介紹GPU虛擬主機建立時間長背後的緣由,以及相關的優化方法。安全
經過分析Libvirt, QEMU以及Guest 內的相關日誌及對應的時間戳,能夠獲取GPU虛擬主機在建立過程當中的耗時狀況,這裏咱們主要關心幾個關鍵的時間點: a) Libvirt 開始建立QEMU 進程;b) Libvirt 執行 Resume啓動VCPU ; c) Guest kernel 打印第一條日誌. 在本文中,咱們把a和 b 之間的時間間隔稱爲QEMU初始化時間, 把b 和c 之間的時間間隔稱爲 BIOS執行時間。如下數據是在滴滴雲的線上環境中採集到的建立一臺包含8個CPU核虛擬機實例的相關數據:性能優化
![](http://static.javashuo.com/static/loading.gif)
從上面的數據能夠看到,對於規格相同的虛擬機實例,帶1塊P40卡的GPU實例相比同規格的CPU實例在QEMU初始化及BIOS執行部分的時間都明顯要長, 在帶4塊P40卡以及更大內存規格的場景下,須要的時間會進一步拉長。經過實驗咱們發如今主機配置和GPU卡型號肯定的前提下,GPU實例的建立時間長短主要取決於兩個因素:虛擬機的內存大小和GPU卡的數量。服務器
爲何GPU實例的建立過程要比CPU實例的建立過程耗時長?多消耗的時間到底花在哪裏?要搞清楚緣由須要深刻的分析,比較直觀的辦法就是經過perf採樣來生成火焰圖,以此來分析虛擬機在建立過程當中的熱點函數。下圖是在滴滴雲環境裏抓取到的GPU虛擬機啓動過程當中QEMU進程的火焰圖。微信
![](http://static.javashuo.com/static/loading.gif)
經過對代碼調用關係的分析,能夠得知熱點發生在系統分配內存和對內存頁面清零的過程當中,是由QEMU中的vfio_dma_map函數在執行VFIO_IOMMU_MAP_DMA ioctl 系統調用所觸發,該調用會Pin住全部分配給VM當作RAM使用的內存。在Pin 內存的過程當中,若是虛擬內存對應的物理頁面還沒有分配,會先進行物理內存分配並對內存頁面內容進行清零。在Linux kernel 中,對分配給應用程序的內存進行清零主要是基於安全方面的考慮,避免Host 內存中的內容泄漏給用戶空間的應用程序。這裏之因此要將內存Pin 住,目的是爲了保證IOMMU IO頁表和 host HVA->HPA 映射的一致性,不然Guest 內設備的DMA操做可能會訪問到錯誤的內存頁面。多線程
VFIO DMA 映射處理慢能夠在必定程度上解釋爲何內存的大小和GPU卡的數量會影響到GPU實例的建立時間。虛擬機實例內存規格越大,須要映射和Pin住的內存量也就越大,相關處理的耗時和內存量成正比。另外GPU卡上一般會包含一塊比較大的MMIO區域,對MMIO的映射也會耗費較多的時間,卡的數量越多,耗時就會越長。相比之下,CPU實例的建立過程沒有VFIO DMA 映射的相關處理流程,所以會比較快。app
針對以上的熱點,有什麼辦法能夠消除或者緩解呢?已經有業內的同行們提到過這個問題並給出了對應的解決方案,其思路是對分配給VM 用做RAM使用的內存區域作一個標記,在內核中跳過對標記的內存頁面進行清零,而將清零的動做留給QEMU來作,在QEMU 中能夠利用多線程以及更高效的指令進行清零動做,從而加速Pin內存的過程。該方案的缺陷主要有兩點: 一是存在安全性風險,其餘應用程序能夠利用設定的標記來窺探host 內存中的信息;二是在VM實例的VCPU個數比較少的狀況下,優化效果不是很好。分佈式
咱們採用了另一種方案,經過修改Host kernel的內存管理部分, 咱們實現了一種對Host 上空閒物理內存提早進行清零的機制,清零動做能夠在系統空閒的時候進行,當某個內存頁面被清零後,將其對應的 struct page 進行標記,這樣在須要對內存進行清零的時候,能夠經過檢查該標記來判斷是否要執行清零動做,若是清零的標記已經被設置,就能夠跳過清零的步驟。該方案避免了上述方案中的兩個主要問題,同時還有其它方面的好處,主要包括如下幾點:a.能夠提升缺頁異常處理效率,尤爲是透明大頁的缺頁異常處理效率;b. 能夠加速須要Pin內存及須要經過mlock 來鎖住內存的應用場景,例如使用RDMA, QAT 硬件加速等場合;c. 能夠加速內核中其餘須要對內存進行清零的場景。相關補丁的RFC版本,咱們已經提交到了Linux kernel 社區。函數
另外一個加速Pin內存的有效方法是採用大頁,經過開啓透明大頁能夠顯著減小缺頁處理的調用次數並加速Pin內存的過程。下圖展現了開啓透明大頁以及啓用空閒內存預清零機制對GPU實例創建立時間的影響。性能
以上的數據代表,在開啓透明大頁以及空閒內存預清零功能後,能夠顯著的的優化QEMU的初始化時間,可是BIOS部分的耗時依然偏長。經過進一步的分析咱們發現主要的時間消耗仍是在VFIO 映射DMA的處理過程中,主要有幾個方面的緣由:a. 映射DMA Pin內存須要逐頁查詢頁表,開銷較大;b. QEMU 存在對部分IOVA區域的反覆映射及解除映射的操做。因而咱們嘗試在這兩個方向上進行優化,經過採用批量處理的方法減小查詢頁表的開銷,另外在QEMU中加入VFIO DMA映射區域的管理,有效的規避了效率低下的反覆映射及解除映射操做,最終大幅度下降了VFIO DMA映射的時間消耗。
在解決完上述問題後咱們並無止步,對虛擬機實例建立過程當中的可優化的其它地方,咱們也作了相關的處理,例如關閉BIOS boot menu ,優化VFIO PCI 設備reset 的流程,去掉對GPU實例來講沒必要要的操做,最終將GPU實例建立過程當中虛擬化部分的時間開銷減小了90%以上,下面這張圖展現了單卡小內存規格實例優化先後的耗時對比:
大內存規格和多GPU卡的效果更加顯著,時間減小了95%以上,相關數據以下圖:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
專一於系統虛擬化研究,負責解決滴滴雲底層虛擬化相關技術問題。曾就任於Intel 開源軟件中心虛擬化組,具有豐富的底層系統軟件開發經驗。
內容編輯 | Charlotte 聯繫咱們 | DiDiTech@didiglobal.com
![]()
本文分享自微信公衆號 - 滴滴技術(didi_tech)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。