實現背景:
在虛機場景下,在virtio的寄存器模塊中,按照現階段的PVF+qid的尋址方式,考慮到虛機場景PVF按照最大2048個計算,現階段有7個寄存器是queue級別的,每個寄存器是32bit,如果按照每個PVF可能對應的65個queue來計算,則總共消耗資源為2048657*32bit= 29,818,880bit,也就至少得1491個M20K的ram。如果后續pvf數量翻倍,那么資源會指數性的增加,這種方式無疑是無法接收的。 所以不能直接用上面的PVF+qid尋址方式,需要進行池化映射。 實際上,我們現在只需要支持最大2K個queue,所以queue級寄存器尋址方式需要進行一級池化,將pvf+qid映射成內部的2k深度的新的地址,就需要一套地址映射,地址管理的機制。
系統框圖
將現在已有的virtio_reg_config模塊里面的queue級寄存器全部提取出來,單獨寫一個模塊(queue_level_reg_config)處理。此模塊包含三個子模塊,分別為queue_remap模塊、addr_manage模塊、reg_manege模塊。 queue_remap模塊:用于地址的映射,回收處理。 addr_manage模塊:地址管理模塊,分配產生池化后的地址。 reg_manege模塊:7組queue級別的寄存器管理。
接口設計
queue_level_reg_config模塊大約有5組配置接口,每一個接口的輸入部分都會攜帶對應的PVF+qid的信息。其中一個是PVF級別的device status寫1或者0接口,用于映射關系建立或者回收;其他幾個是queue_size,avail_addr,desc_addr,used_addr這些要讀寫的寄存器接口。
實現過程
1*、queue_remap模塊處理細節*
- 里面首先有一個地址映射關系表,索引是pvf_id。里面管理的數據內容是65個queue的映射后的地址,還有每個queue有效的標識位。位寬是6511+65=780 bit。這個索引關系表是為了方便地址資源回收、快速獲取映射后的地址。如果后面每個pvf下qid更多,可以考慮將這個ram拆分成幾個。映射關系ram大約如下圖。*
- 寫q級寄存器時,會向地址管理模塊申請地(除了queue_msix_vector寫0xffff,卸載驅動時會執行這個)
- 根據function num 判斷那個是存儲,哪個是網絡,訪問q_szie的時候,存儲返回存儲的q_zize默認值,網絡返回網絡的默認值。
- 地址回收功能。如果檢測到某個pvf_id的device status寫0,就要將這個pvf下所有地址進行回收,傳給地址管理模塊,進行地址分配。
5、addr_manage模塊處理細節
此模塊的主要功能就是新地址的生產和回收。 模塊包含一個比較大的fifo,深度為2048,初始化的時候,寫0到2047數值填滿這個fifo。 如果有queue_remap模塊過來的地址獲取,則會從fifo里面提取一個數值出來,作為新的映射queue地址,并返回一個對應的有效指示信號,對應的就是vld+queue,這個值會寫到queue_remap模塊對應的請求ram中。
初始的時候,假如消耗掉了fifo里面的2048個緩存值,則當queue_remap模塊繼續過來索取新地址時,則不返回vld+queue。因為此時的索取為非法的。 當發生地址回收的時候,即對應的PVF的device status置位為0的時候,queue_remap模塊會將ram中對應的PVF的vld+queue清零,并且,會將清零中對應有效的vld+queue,寫到addr_manege模塊的FIFO中,即為回收這些地址。后續如果有queue_remap模塊來獲取新的映射地址的時候,就會依次從此FIFO中讀出一個值作為新的queue的映射地址。 綜上所述,地址產生的來源有兩個,一個是初始化的時候FIFO中分配的2k個地址,如果這些消耗完了,后續的地址就是靠第二種方式,即通過回收接口回收來獲得。
配置寫寄存器流程
配置寫寄存器時,通過pvf索引映射表,找到對應q的vld是否有效。
如果有效,證明之前獲取過一次地址,就直接用這個地址去寫寄存器。
如果無效,就從地址管理模塊獲取一個地址,用這個地址寫寄存器,并將地址回寫到映射表里,并將vld寫1
配置讀寄存器
同樣,配置讀寄存器的時候,通過pvf索引映射表,查到對應q的vld是否有效,如果有效取出映射后的地址,讀寄存器。如果非有效,證明之前未寫過,或者地址非法,直接返回0
地址回收流程
系統模塊框圖
資源分析:
如果是在2k個pvf,每個pvf下最多33個q,最大支持4K個q的情況下
映射表需要的資源:204833*(11+1)=819200bit 也就是40個m20K*
寄存器地址映射后的需要的資源:4096324=524,288bit也就是大約26個m20k
如果是pvf+qid直接映射,則需要消耗資源大概是324*(2^(10+6))=8,388,608也就是410個m20k,*
相較于直接映射,可以減少300多個m20K
如果是在2k個pvf,每個pvf下最多65個q,最大支持2K個q的情況下
- queue_remap模塊,映射表需要的資源:
204865(11+1)=1,597,440 bit,也就是80個m20K 。
- addr_manage模塊,緩存映射后的queue地址的FIFO消耗的資源:
2048*11= 1,也就是1個m20K
(3)reg_manege模塊,實際存放queue級別寄存器的資源消耗:
2048327=458,752 bit也就是大約23個m20k
總共需要80+1+23 = 104個M20k
如果是pvf+qid直接映射,則需要消耗資源大概是2048657*32bit= 29,818,880bit,也就至少得1491。
相較于直接映射,新池化的方案,可以減少1387多個m20K。
注意事項
需要注意模塊之間的時序開銷,尤其是queue_remap模塊與addr_manege模塊之間的地址獲取和釋放的過程中,所需要消耗的時鐘周期,因此最好是在queueu_remap開頭處加一個緩存的fifo,用于緩存所有的輸入進來的PVF+qid讀寫寄存器的請求。只有當處理完一個完整的映射后,再進行下一個請求的響應。以免引起時序上的錯誤。