浪潮資訊工程師:帶你瞭解裝置透傳虛擬機器的快速啟動技術最佳化方案 | 龍蜥技術
編者按:將物理裝置透過 vfio 透傳給虛擬機器是虛擬化常用的技術,但當為虛擬機器分配比較大的記憶體時,虛擬機器的啟動時間會明顯變慢,可能由十幾秒延長至數分鐘,嚴重影響使用者使用體驗。本文整理自 龍蜥大講堂 51 期,浪潮資訊作業系統研發工程師參與技術分享,介紹了裝置透傳虛擬機器啟動慢的原因及最佳化方法,以下為此次分享內容:
技術背景:大記憶體虛擬機器裝置透傳啟動延遲
虛擬機器裝置透傳時存在問題,比如將網路卡或者 GPU 這些 pci 裝置透過宿主機的 vfio 透傳到虛擬機器,並且又為虛擬機器分配了比較大的記憶體時,虛擬機器的啟動時間會明顯變慢。特別是分配了幾百 G,甚至上 TB 的記憶體時,就會有比較明顯的啟動延遲,可能由十幾秒延遲到數分鐘。由於只有第一次啟動時,也就是 qemu 程式啟動時才會影響,所以一般來說使用者可以接受這個啟動延遲,但如果使用者有頻繁建立銷燬虛擬機器的需求時就會有比較差的使用體驗。
把裝置透傳到虛擬機器內部之後將會使用虛擬機器內部的驅動程式對裝置進行操作,這裡有一個重要的問題是在虛擬機器內部該如何進行 DMA 操作,因為 DMA 是不會經過 CPU 的,所以使用的是實體地址,但虛擬機器內部看到的實體地址實際上只是宿主機上 qemu 程式申請的虛擬地址,直接用來做 DMA 肯定是不行的。這裡就需要藉助 IOMMU 來實現,虛擬機器內 DMA 訪問的 GPA,經過 iommu 對映到宿主機上的實體地址 HPA2,另外虛擬機器內的驅動程式也可以經過 MMU/EPT,把 GVA 對映為 HPA1,最終需要 HPA1 和 HPA2 這兩個實體地址是同一個才能讓裝置正常執行。(如下圖)
為了實現 HPA1 等於 HPA2,需要 GPA 到 HPA 的對映是固定的並進行 iommu 表的建立,vfio 是透過 VFIO_IOMMU_MAP_DMA 命令實現。
後面使用到了 free page reporting 機制,這裡介紹下 free page reporting 機制的原理,首先該機制提供了回撥函式的註冊,每隔 2 秒會遍歷每個 zone 中的空閒頁並呼叫回撥函式進行處理,但只處理 buddy 中高階記憶體頁,就是 pageblock_order 階及以上的記憶體,在 X86 架構下就是處理 9 階和 10 階的記憶體頁,也就是 2M 和 4M 的記憶體頁,這樣也是保證能夠處理 2M 的透明大頁。
另一方面在處理時會保證每個 zone 的水線要比最低水線高 64M,因為如果 zone 的水線本身已經夠低了,還從 zone 中申請記憶體,可能就會觸發記憶體回收,這就會影響一些程式的效能。
通記憶體預清零加速 qemu 程式的記憶體初始化過程
下圖是一個虛擬機器啟動時的火焰圖,這裡的虛擬機器啟動是指 qemu 程式開始執行到虛擬機器內部出現 BIOS 介面為止,不包括虛擬機器內部的核心載入、服務執行過程,從火焰圖可以看到最耗時的函式是 clear_subpage 函式,根據函式呼叫關係可以看到是從 qemu 端呼叫了 ioctl 系統呼叫,這裡就是要將虛擬機器記憶體大小的虛擬記憶體執行 iommu 對映工作,將虛擬地址對映到指定的實體地址上。這其中就需要先將虛擬地址執行 page fault,並將虛擬機器地址和實體地址的關係固定下來,再執行 iommu 對映操作。
應用程式執行 page fault 時最終都會執行 clear_user_highpage 對記憶體進行清零操作,這個函式相對來說耗時較長,是虛擬機器啟動時間慢的重要原因,當然我們可以選擇不進行記憶體清零,但這會把宿主機上的一些敏感資訊傳遞給虛擬機器,造成安全影響,所以一般我們需要對記憶體進行清零。
為了解決記憶體頁清零耗時比較長的問題,我們可以基於 free page reporting 機制實現記憶體頁的預清零,過程比較簡單,這裡簡單說下原理。首先透過 free page reporting 介面註冊自己的 hook 函式,然後這個 hook 函式會週期性的被呼叫,每次呼叫會將 buddy 中的 2M/4M 空閒頁執行清零操作,並在 page 的 flag 上設定清零 flag,最後在應用程式申請的記憶體觸發缺頁異常並需要對記憶體進行清零時,會首先判斷該頁是否已經設定了清零 flag,如果已設定則跳過耗時較長的清零操作。還有一點就是記憶體頁的清零屬於耗時但不緊急的操作,如果當前 CPU 有其它的事情要做,則優先執行別的工作,只有在 CPU 空閒時才執行記憶體清零。
透過大塊記憶體 pin 降低 qemu 的記憶體 pin 時間
下圖是最佳化了記憶體頁預清零之後的火焰圖,可以看到 clear_user_page 函式的執行時間已經非常短了,總體執行時間比較長的幾個函式是 follow_page_mask、handle_mm_fault、find_extern_vma,下面就從程式碼角度來看哪個函式還可以進行最佳化。
vfio_pin_map_dma(…) { while(size) { npage = vfio_pin_pages_remote(dma,start_vaddr,size,&pfn,limit) vfio_iommu_map(iommu,start_vaddr,pfn,npage,true) }將實體地址連續的記憶體執行iommu map }
IOMMU_MAP_DMA 的 ioctl 進入核心空間會執行到 vfio_pin_map_dma 函式,在這個函式里會對虛擬機器記憶體大小的虛擬記憶體進行 iommu map 操作,首先呼叫 vfio_pin_pages_remote 進行記憶體 pin 操作,這個函式的返回值 npage 是實體地址連續的N個記憶體頁,然後呼叫 vfio_iommu_map 執行 iommu map 操作,比如對於 500G 記憶體的虛擬機器來說會執行很多次這兩個函式。
vfio_pin_pages_remote(…) { for (…) { pin_user_pages_remote(NULL, mm, vaddr, 1, flags | FOLL_LONGTERM, page, NULL, NULL); pfn = page_to_pfn(page[0]); if(pfn != *pfn_base + pinned) break; }每次只pin一個page,然後判斷和上一個page是否物理連續 }
vfio_pin_pages_remote 這個函式會返回物理連續的多個記憶體頁,為了實現這功能,每次呼叫 pin_user_pages_remote 獲取一個頁,然後判斷和上一個頁是否物理連續。
get_user_pages(…) { while(npages) { if(!vma || start >= vma->vm_end)//相鄰的兩個虛擬記憶體頁是否屬於同一個vma { vma = find_extern_vma(…) } page = follow_page_mask(vma,start,…); if(!page) faultin_page(…) } }
前面說的 pin_user_pages_remote 函式執行了很多次,這個函式里主要是呼叫了 get_user_pages,根據需要 pin 的 page 個數,首先判斷相鄰的兩個虛擬記憶體頁是否屬於同一個 vma,如果不是則呼叫 find_extern_vma 函式獲取 vma,這個函式從火焰圖來看也是耗時比較長的,下面就是執行 follow_page_mask 獲取頁表,如果還未分配物理頁則呼叫 page fault。
後面的兩個函式執行是無法避免的,現在就看 find_extern_vma 函式,因為虛擬機器的實體記憶體是 qemu mmap 的連續虛擬記憶體,屬於同一個 vma,所以每次如果 pin 多個 page 可以跳過頻繁執行的 find_extern_vma。
下面看一下核心社群的最佳化方案,5.12 核心合入主線,透過修改 vfio 程式碼實現,commit 說明有 8% 的效能提升。
最佳化原理是在 pin_user_pages_remote 函式里每次獲取 512 個 page,當然這些page可能是不連續的,然後將這 512 個 page 中連續的部分識別出來分別執行iommu,因為我們系統中是開啟透明大頁的,所以一般來說這 512 個 page 都是物理連續的,只需要執行一次 iommu 就可以。
測試結果
測試環境為虛擬機器分配了 512G 的記憶體,做了網路卡的裝置透傳,虛擬機器的啟動時間計算方法為從 qemu 程式啟動開始到出現 grub 介面為止,還有就是記憶體預清零在最理想的情況下,即當前系統上所有的 free page 已經清零完畢。
最終的測試結果:預設情況下(即開啟透明大頁),如果只開啟大塊記憶體 pin,啟動時間從 80 秒降低至 60 秒,如果再開啟記憶體頁預清零,啟動時間將降低至 12 秒。再看下虛擬機器記憶體使用大頁記憶體的情況下的測試結果,在使用 2M 或 1G 大頁時開啟大塊記憶體 pin 功能時,虛擬機器的啟動時間基本從 36 秒降低至 18 秒,就算在開啟記憶體頁預清零,啟動時間也沒有變化,因為記憶體預清零不能作用於標準大頁。
-
虛擬機器分配 512G 記憶體。
-
時間計算方法:time vrish start testvm,時間為從 qemu 啟動到出現 grub 介面為止。
-
記憶體預清零在最理想情況下,即當前系統上所有 free page 已經清零完畢。
關於直播課件及影片回放獲取方式:
【PPT 課件獲取】:關注微信公眾號(OpenAnolis),回覆“龍蜥課件” 即可獲取。有任何疑問請隨時諮詢龍蜥助手—小龍(微信:openanolis_assis)。
【影片回放】:影片回放可前往龍蜥官網檢視。
—— 完 ——
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70004278/viewspace-2925205/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 浪潮資訊工程師:談一談裝置透傳虛擬機器啟動慢背後的原因及其最佳化方法 | 第 51 期工程師虛擬機
- 虛擬化解決方案 virtio 的技術趨勢與 DPU 實踐解讀 | 龍蜥技術
- 容器技術和虛擬機器技術的對比虛擬機
- 技術門檻高?來看 Intel 機密計算技術在龍蜥社群的實踐 | 龍蜥技術Intel
- 雲集技術學社|帶你瞭解DevOps技術原理dev
- 反虛擬機器技術總結虛擬機
- 一文帶你瞭解HDFS技術
- 致敬 hacker :盤點記憶體虛擬化探索之路|龍蜥技術記憶體
- 技術解讀倚天 ECS 例項——Arm 晶片的 Python-AI 算力最佳化 | 龍蜥技術晶片PythonAI
- AI技術為TPM裝置管理帶來了新的解決方案AI
- Docker技術( 容器虛擬化技術 )Docker
- 一、你瞭解機器學習技術體系嗎機器學習
- 助力Koordinator雲原生單機混部,龍蜥混部技術提升CPU利用率達60%|龍蜥技術
- LUA指令碼虛擬機器逃逸技術分析指令碼虛擬機
- 虛擬蜜罐:從資訊模擬到實現虛擬蜜罐技術
- 龍蜥社群聯合浪潮資訊釋出《eBPF技術實踐白皮書》(附下載連結)eBPF
- 深入解讀雲場景下的網路抖動 | 龍蜥技術
- 技術工坊|WASM應用區塊鏈虛擬機器的技術實踐(上海)ASM區塊鏈虛擬機
- 發動機產品快速配置技術PDM解決方案
- 帶你瞭解DDOS防禦中流量清洗的技術方法
- 技術分享:瞭解 Spring Boot 啟動類 SpringApplicationSpring BootAPP
- 虛擬化技術之kvm虛擬機器建立工具virt-install虛擬機
- 虛擬化技術之kvm虛擬機器建立工具qemu-kvm虛擬機
- 虛擬機器遷移技術原理與應用虛擬機
- 帶你瞭解騰訊開源的多渠道打包技術 VasDolly原始碼解析原始碼
- 一文解讀機密容器的崛起和發展 | 龍蜥技術
- 虛擬現實技術
- 技術解讀:Dragonfly 基於 P2P 的智慧映象加速系統 | 龍蜥技術Go
- 瞭解VR虛擬現實的沉浸式效果及其技術特點!VR
- 深入淺出解讀 Java 虛擬機器的差別測試技術Java虛擬機
- 伺服器虛擬化技術的優點伺服器
- 學術乾貨|深入淺出解讀 Java 虛擬機器的差別測試技術Java虛擬機
- 技術界中的虛擬機器、容器和沙箱的關係虛擬機
- 虛擬模擬部署新方案-畫素流技術
- 虛擬化四、KVM虛擬化技術
- 如何透過 open-local 玩轉容器本地儲存? | 龍蜥技術
- win10虛擬化技術怎麼開啟_win10系統cpu虛擬化技術如何開啟Win10
- 伺服器虛擬化技術深度科普伺服器