日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

以 rte_mempool_ops_table 为例描述 dpdk 程序库链接顺序对程序执行的影响

發(fā)布時間:2024/3/12 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 以 rte_mempool_ops_table 为例描述 dpdk 程序库链接顺序对程序执行的影响 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

dpdk mempool_ops

dpdk mempool_ops 是對舊版 mempool 代碼的抽象,在 dpdk-16.07 中被引入。

老版本在創(chuàng)建 mempool 時會創(chuàng)建一個內(nèi)部的 ring 來完成入隊與出隊的操作,底層區(qū)分了多生產(chǎn)者、多消費者,單生產(chǎn)者、單消費者模型。

老版本 mempool 創(chuàng)建時會將所有的元素預(yù)先 enqueue 到 ring 中,并對每個元素執(zhí)行初始化操作,這部分代碼隱含在 mempool 的內(nèi)部實現(xiàn)中。用戶從 mempool 中申請、釋放 mem,最底層是通過 dequeue、enqueue ring 來實現(xiàn)的。

隨著 dpdk 支持場景的拓寬,在 mempool 底層使用 ring 這一種數(shù)據(jù)結(jié)構(gòu)來控制 mem 的申請與釋放不能滿足所有場景的使用需求

在一些場景下,一些外部的內(nèi)存子系統(tǒng)在使用 DPDK 時需要對 mempool 底層的入隊與出隊的行為進(jìn)行定制化開發(fā),這意味著底層的這部分功能需要向外部開放,必須能夠讓程序注冊一個自定義的入隊、出隊方法及關(guān)聯(lián)數(shù)據(jù)結(jié)構(gòu),rte_mempool_ops 就是這種功能的具體實現(xiàn)。

rte_mempool_ops 的抽象

16.07 中 rte_mempool_ops 的定義如下:

struct rte_mempool_ops {char name[RTE_MEMPOOL_OPS_NAMESIZE]; /**< Name of mempool ops struct. */rte_mempool_alloc_t alloc; /**< Allocate private data. */rte_mempool_free_t free; /**< Free the external pool. */rte_mempool_enqueue_t enqueue; /**< Enqueue an object. */rte_mempool_dequeue_t dequeue; /**< Dequeue an object. */rte_mempool_get_count get_count; /**< Get qty of available objs. */ } __rte_cache_aligned;

name 用于唯一標(biāo)識每個 mempool_ops,alloc 用于 mempool_ops 內(nèi)部數(shù)據(jù)結(jié)構(gòu)的創(chuàng)建,free 用于 mempool_ops 內(nèi)部數(shù)據(jù)結(jié)構(gòu)的銷毀,enqueue 負(fù)責(zé)入隊列,dequeue 負(fù)責(zé)出隊列,get_count 用以獲取當(dāng)前可用的對象數(shù)量。

總結(jié)起來有如下三部分功能:

  • mempool_ops 內(nèi)部數(shù)據(jù)結(jié)構(gòu)的創(chuàng)建與釋放功能
  • mempool_ops 對象的入隊與出隊功能
  • mempool_ops 底層可用對象數(shù)量的查詢功能
  • 以 ring 描述在 mempool_ops 框架下 mempool_ops 的使用過程

    每一個 mempool_ops 需要實例化一個 rte_mempool_ops 結(jié)構(gòu)并將此結(jié)構(gòu)注冊到系統(tǒng)中,對單生產(chǎn)者與單消費者這種基于 ring 的模型而言它實例化的 rte_mempool_ops 定義如下;

    static const struct rte_mempool_ops ops_sp_sc = {.name = "ring_sp_sc",.alloc = common_ring_alloc,.free = common_ring_free,.enqueue = common_ring_sp_enqueue,.dequeue = common_ring_sc_dequeue,.get_count = common_ring_get_count, };

    使用如下命令注冊:

    MEMPOOL_REGISTER_OPS(ops_sp_sc);

    MEMPOOL_REGISTER_OPS 通過 gcc 的構(gòu)造函數(shù)聲明,調(diào)用 rte_mempool_register_ops 函數(shù)將 ops_sp_sc mempool_ops 注冊到系統(tǒng)中。

    rte_mempool_register_ops 在進(jìn)行一系列的內(nèi)容檢查后,將 ops_sp_sc 注冊到 rte_mempool_ops_table 表中(在獲取到互斥鎖的前提下,保證對 rte_mempool_ops_table 的互斥訪問)。

    成功后,會獲取到 ops_indexops 在 rte_mempool_ops_table 中的下標(biāo)),這個下標(biāo)會被保存到 mempool 結(jié)構(gòu)的 ops_index 字段中(通過調(diào)用 rte_mempool_set_ops_byname 函數(shù)設(shè)置)。

    其功能定義如下:

    /*** Index into rte_mempool_ops_table array of mempool ops* structs, which contain callback function pointers.* We're using an index here rather than pointers to the callbacks* to facilitate any secondary processes that may want to use* this mempool.*/int32_t ops_index;

    mempool_ops 被調(diào)用的地方

    使用 mempool_ops 時,通過 rte_mempool_get 函數(shù)出隊列過程函數(shù)調(diào)用圖示如下:


    當(dāng) cache 中沒有緩存時,就調(diào)用底層 ops 中注冊的 dequeue 接口來完成。

    dpdk-16.07 中相關(guān) git commit

    相關(guān)的 commit 信息如下:

    commit 449c49b93a6b87506c7bb07468e82b539efddca3 Author: David Hunt <david.hunt@intel.com> Date: Wed Jun 22 10:27:27 2016 +0100mempool: support handler operationsUntil now, the objects stored in a mempool were internally stored in aring. This patch introduces the possibility to register external handlersreplacing the ring.The default behavior remains unchanged, but calling the new functionrte_mempool_set_ops_byname() right after rte_mempool_create_empty() allowsthe user to change the handler that will be used when populatingthe mempool.This patch also adds a set of default ops (function callbacks) basedon rte_ring.Signed-off-by: David Hunt <david.hunt@intel.com>Signed-off-by: Olivier Matz <olivier.matz@6wind.com>Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>Acked-by: Olivier Matz <olivier.matz@6wind.com>

    此接口在后面的版本有一些優(yōu)化,但是主體框架沒有大的變動。注冊一個自己的 mempool_ops 的實例可以參照 vpp dpdk_plugins 中的實現(xiàn)代碼

    19.11 中 dpdk 程序初始化后 rte_mempool_ops_table 的布局情況

    dpdk-19.11 中 dpdk 程序初始化后 rte_mempool_ops_table 結(jié)構(gòu)示例如下圖:

    上圖中,rte_mempool_ops_table 的不同表項指向不同的 mempool_ops 實例。

    使用靜態(tài)庫時,鏈接不同 mempool_ops 所在庫的順序決定了 rte_mempool_ops_table 中不同 mempool_ops布局。如果 dpdk primary 進(jìn)程與 secondary 進(jìn)程鏈接不同 mempool_ops 構(gòu)造函數(shù)所在庫的順序不同,則會有不同的 rte_mempool_ops_table 布局,當(dāng) mempool 需要在 primary 與 secondary 中共享時,不同的 rte_mempool_ops_table 布局就會帶來嚴(yán)重的問題!

    第一種布局方式——dpdk 內(nèi)部示例程序的布局

    這里以 dpdk-pdump 為代表,其鏈接參數(shù)可以查看如下文件:

    x86_64-native-linuxapp-gcc/build/app/pdump/.dpdk-pdump.cmd

    此種方式下 rte_mempool_ops_table 的前 4 個元素布局情況見下圖:
    可以看到,mp_mc 這種基于 ring 的多生產(chǎn)者與多消費者占據(jù) rte_mempool_ops_table 表中 ops 數(shù)組的第一個表項,examples 目錄下的 dpdk primary 程序中 rte_mempool_ops_table 表的布局與 app 下的程序布局一致。

    使用 libdpdk.a 鏈接外部程序時的布局情況

    libdpdk.a 中 mempool 相關(guān)靜態(tài)庫的鏈接順序如下:

    cat ./x86_64-native-linux-gcc/lib/libdpdk.a GROUP (...librte_mempool_bucket.a librte_mempool_dpaa2.a librte_mempool_octeontx.a librte_mempool_octeontx2.a librte_mempool_ring.a librte_mempool_stack.a ...)

    此時程序運行后,rte_mempool_ops_table 表中 mempool_ops 的布局情況見下圖:

    可以看到,此時 mempool_bucket_ops 占據(jù) rte_mempool_ops_table 中 ops 的第一個元素,這與第一種情況是不同的。

    問題描述

    primary 進(jìn)程使用 libdpdk.a 中的鏈接順序,使用第二種 rte_mempool_ops_table 布局方式,secondary 進(jìn)程使用 dpdk-pdump,使用此程序來抓取報文。

    問題現(xiàn)象:

    打流情況下,dpdk-pdump 程序運行起來后會導(dǎo)致 primary 進(jìn)程段錯誤。

    dpdk-pdump dump 報文的原理淺析

    dpdk-pdump 首先創(chuàng)建 pdump_tuples 中使能表項的不同字段,一個 pdump_tuples 表項 能夠完整的描述一個待 dump 的目標(biāo)接口。

    dpdk-pdump 會為每一個 pdump_tuples 創(chuàng)建單獨的 pktmbuf_pool 并使用 mp_mc_ops 這種 mempool_ops,同時會根據(jù)配置的功能,來創(chuàng)建相應(yīng)的 ring

    pdump_tuples 及 vdev 接口初始化完成后dpdk-pdump 會調(diào) rte_pdump_enable_by_deviceid 來使能 dump 指定接口指定隊列上指定收、方向報文的功能。

    rte_pdump_enable_by_deviceid 會使用 pdump_tuples 中配置表項的內(nèi)容作為參數(shù),構(gòu)造一條請求,然后將這條請求通過本地套接字發(fā)送給 primary 進(jìn)程。

    primary 進(jìn)程收到這條消息后,進(jìn)行解析并調(diào)用 pdump_server 函數(shù),pdump_server 調(diào)用 set_pdump_rxtx_cbs 來向請求的 port 與 queue 的 rx、tx 方向注冊回調(diào)函數(shù),rx 這方為 pdump_rx,tx 這方為 pdump_tx

    完成了上述操作后,pdump_server 會向?qū)Ψ桨l(fā)送一個 reply,表明配置狀態(tài)。

    當(dāng)程序調(diào)用 rte_eth_rx_burst 時,成功收到報文后,會遍歷接收回調(diào)函數(shù)并執(zhí)行,在這里就調(diào)用到了 pdump_rx 函數(shù)。

    pdump_rx 函數(shù)使用 dpdk-pdump 發(fā)送請求中指定的 mempool 來申請 mbuf,然后拷貝報文到 mbuf 中,成功后就嘗試將報文投遞到 dpdk-pdump 發(fā)送請求中指定的 ring 中,失敗則直接釋放報文。

    由于 dpdk 程序在初始化的過程中已經(jīng)執(zhí)行了一些內(nèi)存的共享操作,primary 進(jìn)程能夠直接使用 secondary 進(jìn)程中的一些虛擬地址,這里的 mempool 的地址就是一個實例。

    問題就出在這里!當(dāng) primary 進(jìn)程收到包后,調(diào)用到 pdump_rx 函數(shù)時,在從 mempool 中申請 mbuf 的時候,由于 dpdk-pdump 與 primary 進(jìn)程的 rte_mempool_ops_table 表中 mempool_ops 的布局不同,在 dpdk-pdump 對應(yīng) ops_mp_mc 這個 mempool_ops 的表項處,在 primary 進(jìn)程中實際對應(yīng)的是 bucketmempool_ops,就造成了 primary 進(jìn)程段錯誤

    解決方案

    調(diào)整 libdpdk.a 中 mempool_ops 所在庫的鏈接順序,與 dpdk-pdump 保持一致,重新編譯 primary 程序。

    總結(jié)

    本文從 rte_mempool_ops 著手描述,目的在于說明由于庫鏈接順序的區(qū)別導(dǎo)致 dpdk primary 進(jìn)程與 secondary 進(jìn)程中 mempool_ops 在 rte_mempool_ops_table 占據(jù)不同的表項,進(jìn)一步造成程序段錯誤的問題。

    使用 gcc 的 constructor 修飾符來聲明構(gòu)造函數(shù),在使用靜態(tài)庫的情況下,鏈接順序就決定了初始化的順序,進(jìn)而影響到了在不同程序中表單的布局,這一布局又隨著多個程序之間的交互被誤用,最終造成了嚴(yán)重的問題。

    使用 constructor 修飾符讓 mempool_ops 的動態(tài)添加變得非常簡單,避免了硬編碼。但是使用了 constructor 的同時也繼承了 constructor 潛在的問題,即鏈接的順序決定了初始化的順序,這算是種隱式的依賴,不太容易發(fā)現(xiàn)!

    正如一件事物有好有壞,一個技術(shù)也有好有壞,更準(zhǔn)確點說應(yīng)該是有優(yōu)勢也有限制條件。我們應(yīng)當(dāng)做到既清楚它的優(yōu)勢也清楚它的限制條件,正如我們需要明悟自己的長短一般,并不是那么容易!

    本篇文章算是使用 groff 繪圖的一個開端,繪出的圖讓人挺滿意的,這是一個很好的開端,也是一個改變的點。

    最后將 mempool_ops 中某張圖片的 pic 代碼貼到下面,僅供參考!

    .PSdefine rte_mempool_ops { box "..........";box $1 fill 0.4;box $2 fill 0.6;}boxht=0.4; boxwid=2.5;A:box "sl"; down; box "num_ops" with .nw at A.sw; B:box "ops[0]" fill 0.5; C:box "ops[1]" fill 0.5; D: box "ops[2]" fill 0.5; E: box "ops[3]" fill 0.5; F:box "ops[...]" fill 0.5;boxwid=1.8;H:box "octeontx" with .nw at A.se + (2, -4) fill 0.2; rte_mempool_ops("otx2_npa_enq", "otx2_npa_deq");I:box "dpaa" with .nw at A.e + (2, 0.5) fill 0.2; rte_mempool_ops("dpaa_mbuf_free_bulk", "dpaa_mbuf_alloc_bulk");J:box "bucket" with .nw at A.se + (2, 3) fill 0.2; rte_mempool_ops("bucket_enqueue", "bucket_dequeue");K:box "dpaa2" with .nw at A.se + (2, -1.5) fill 0.2; rte_mempool_ops("irte_hw_mbuf_free_bulk", "rte_dpaa2_mbuf_alloc_bulk");"\fBrte_mempool_ops_table\fR" textwid 2 with .nw at A.c + (0, 0.4); "\fB mempool_octeontx_ops\fR" textwid 2 with .nw at H.c + (0, 0.4); "\fB mempool_dpaa_ops\fR" textwid 2 with .nw at I.c + (0, 0.4); "\fB mempool_bucket_ops\fR" textwid 2 with .nw at J.c + (0, 0.4); "\fB mempool_dpaa2_ops\fR" textwid 2 with .nw at K.c + (0, 0.4);line chop 0 chop 0 from B.e to J.w ->; line chop 0 chop 0 from C.e to I.w ->; line chop 0 chop 0 from D.e to K.w ->; line chop 0 chop 0 from E.e to H.w ->;

    總結(jié)

    以上是生活随笔為你收集整理的以 rte_mempool_ops_table 为例描述 dpdk 程序库链接顺序对程序执行的影响的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。