DPDK mempool


Mempool 庫

內存池是固定大小的對象分配器。 在DPDK中,它由名稱唯一標識,並且使用mempool操作來存儲空閑對象。 默認的mempool操作是基於ring的。它提供了一些可選的服務,如per-core緩存和對齊幫助,以確保對象被填充, 方便將他們均勻擴展到DRAM或DDR3通道上。

這個庫由 Mbuf Library 使用。

1.1. Cookies

在調試模式(CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG is enabled)中,將在塊的開頭和結尾處添加cookies。 分配的對象包含保護字段,以幫助調試緩沖區溢出。

1.2. Stats

在調試模式(CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG is enabled)中,從池中獲取/釋放的統計信息存放在mempool結構體中。 統計信息是per-lcore的,避免並發訪問統計計數器。

1.3. 內存對齊約束

根據硬件內存配置,可以通過在對象之間添加特定的填充來大大提高性能。 其目的是確保每個對象開始於不同的通道上,並在內存中排列,以便實現所有通道負載均衡。

特別是當進行L3轉發或流分類時,報文緩沖對齊尤為重要。此時僅訪問報文的前64B,因此可以通過在不同的信道之間擴展對象的起始地址來提升性能。

DIMM上的rank數目是可訪問DIMM完整數據位寬的獨立DIMM集合的數量。 由於他們共享相同的路徑,因此rank不能被同事訪問。 DIMM上的DRAM芯片的物理布局無需與rank數目相關。

當運行app時,EAL命令行選項提供了添加內存通道和rank數目的能力。

Note

命令行必須始終指定處理器的內存通道數目。

不同DIMM架構的對齊示例如圖所示 Fig. 5.1Fig. 5.2

../_images/memory-management.svg

Fig. 5.1 Two Channels and Quad-ranked DIMM Example

在這種情況下,假設吧平穩是64B塊就不成立了。

Intel® 5520芯片組有三個通道,因此,在大多數情況下,對象之間不需要填充。(除了大小為n x 3 x 64B的塊)

../_images/memory-management2.svg

Fig. 5.2 Three Channels and Two Dual-ranked DIMM Example

當創建一個新池時,用戶可以指定使用此功能。

1.4. 本地緩存

在CPU使用率方面,由於每個訪問需要compare-and-set (CAS)操作,所以多核訪問內存池的空閑緩沖區成本比較高。 為了避免對內存池ring的訪問請求太多,內存池分配器可以維護per-core cache,並通過實際內存池中具有較少鎖定的緩存對內存池ring執行批量請求。 通過這種方式,每個core都可以訪問自己空閑對象的緩存(帶鎖), 只有當緩存填充時,內核才需要將某些空閑對象重新放回到緩沖池ring,或者當緩存空時,從緩沖池中獲取更多對象。

雖然這意味着一些buffer可能在某些core的緩存上處於空閑狀態,但是core可以無鎖訪問其自己的緩存提供了性能上的提升。

緩存由一個小型的per-core表及其長度組成。可以在創建池時啟用/禁用此緩存。

緩存大小的最大值是靜態配置,並在編譯時定義的(CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE)。

Fig. 5.3 顯示了一個緩存操作。

../_images/mempool.svg

Fig. 5.3 A mempool in Memory with its Associated Ring

不同於per-lcore內部緩存,應用程序可以通過接口 rte_mempool_cache_create()rte_mempool_cache_free()rte_mempool_cache_flush() 創建和管理外部緩存。 這些用戶擁有的緩存可以被顯式傳遞給 rte_mempool_generic_put()rte_mempool_generic_get() 。 接口 rte_mempool_default_cache() 返回默認內部緩存。 與默認緩存相反,用戶擁有的高速緩存可以由非EAL線程使用。

1.5. Mempool 句柄

這允許外部存儲子系統,如外部硬件存儲管理系統和軟件存儲管理與DPDK一起使用。

mempool 操作包括兩方面:

  • 添加新的mempool操作代碼。這是通過添加mempool ops代碼,並使用 MEMPOOL_REGISTER_OPS 宏來實現的。
  • 使用新的API調用 rte_mempool_create_empty()rte_mempool_set_ops_byname() 用於創建新的mempool,並制定用戶要使用的操作。

在同一個應用程序中可能會使用幾個不同的mempool處理。 可以使用 rte_mempool_create_empty() 創建一個新的mempool,然后用 rte_mempool_set_ops_byname() 將mempool指向相關的 mempool處理回調(ops)結構體。

傳統的應用程序可能會繼續使用舊的 rte_mempool_create() API調用,它默認使用基於ring的mempool處理。 這些應用程序需要修改為新的mempool處理。

對於使用 rte_pktmbuf_create() 的應用程序,有一個配置設置(RTE_MBUF_DEFAULT_MEMPOOL_OPS),允許應用程序使用另一個mempool處理。

1.6. Mempool

DPDK以兩種方式對外提供內存管理方法,一個是rte_mempool,主要用於網卡數據包的收發;一個是rte_malloc,主要為應用程序提供內 存使用接口。本文討論rte_mempool。rte_mempool由函數rte_mempool_create()負責創建,從 rte_config.mem_config->free_memseg[]中取出合適大小的內存,放到 rte_config.mem_config->memzone[]中。

rte_mempool結構體:

 1 /**
 2  * The RTE mempool structure.
 3  */
 4 struct rte_mempool {
 5     /*
 6      * Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI
 7      * compatibility requirements, it could be changed to
 8      * RTE_MEMPOOL_NAMESIZE next time the ABI changes
 9      */
10     char name[RTE_MEMZONE_NAMESIZE]; /**< Name of mempool. */
11     RTE_STD_C11
12     union {
13         void *pool_data;         /**< Ring or pool to store objects. */
14         uint64_t pool_id;        /**< External mempool identifier. */
15     };
16     void *pool_config;               /**< optional args for ops alloc. */
17     const struct rte_memzone *mz;    /**< Memzone where pool is alloc'd. */
18     unsigned int flags;              /**< Flags of the mempool. */
19     int socket_id;                   /**< Socket id passed at create. */
20     uint32_t size;                   /**< Max size of the mempool. */
21     uint32_t cache_size;
22     /**< Size of per-lcore default local cache. */
23 
24     uint32_t elt_size;               /**< Size of an element. */
25     uint32_t header_size;            /**< Size of header (before elt). */
26     uint32_t trailer_size;           /**< Size of trailer (after elt). */
27 
28     unsigned private_data_size;      /**< Size of private data. */
29     /**
30      * Index into rte_mempool_ops_table array of mempool ops
31      * structs, which contain callback function pointers.
32      * We're using an index here rather than pointers to the callbacks
33      * to facilitate any secondary processes that may want to use
34      * this mempool.
35      */
36     int32_t ops_index;
37 
38     struct rte_mempool_cache *local_cache; /**< Per-lcore local cache */
39 
40     uint32_t populated_size;         /**< Number of populated objects. */
41     struct rte_mempool_objhdr_list elt_list; /**< List of objects in pool */
42     uint32_t nb_mem_chunks;          /**< Number of memory chunks */
43     struct rte_mempool_memhdr_list mem_list; /**< List of memory chunks */
44 
45 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG
46     /** Per-lcore statistics. */
47     struct rte_mempool_debug_stats stats[RTE_MAX_LCORE];
48 #endif
49 }  __rte_cache_aligned;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM