0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

发烧友实测 | i.MX8MP 编译DPDK源码实现rte_ring无锁环队列进程间通信

飞凌嵌入式 2022-01-10 16:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

ad6972f6-6fd6-11ec-86cf-dac502259ad0.jpg

作者|donatello1996

来源 | 电子发烧友

题图|飞凌嵌入式

rte_ring是一个用CAS实现的无锁FIFO环形队列,支持多消费者/生产者同时出入队列,常用于多线程/多进程之间的通信。具体原理可以查看DPDK官方文档或者阅读源码,本文采用的硬件板卡为飞凌嵌入式OKMX8MP-C开发板,系统版本Linux5.4.70+Qt5.15.0,主要介绍通过编译DPDK源码实现rte_ring无锁环队列进程间通信

下面就跟着小编一起了解下。

一、内核编译

下载并解压飞凌厂商提供的iMX8MP内核源码压缩包分卷:

ad94f48a-6fd6-11ec-86cf-dac502259ad0.jpg

在虚拟机中合并压缩分卷并解压得出内核源码包文件夹OK8MP-linux-kernel,将文件夹使用tar打包并复制到TF卡文件系统中解压:

adcb86f8-6fd6-11ec-86cf-dac502259ad0.jpg

找到内核源码中的配置文件OK8MP-C_defconfig:

ade9250a-6fd6-11ec-86cf-dac502259ad0.jpg

这个就是make选项,使用

make OK8MP-C_defconfig

指令即可配置编译选项:

make -j4

开始编译:

注意开始编译前需要安装常用软件:

apt install bison bc flex

ae1a54cc-6fd6-11ec-86cf-dac502259ad0.jpg

ae5d461a-6fd6-11ec-86cf-dac502259ad0.jpg

增量编译完毕:

ae99b79e-6fd6-11ec-86cf-dac502259ad0.jpg

二、DPDK编译

接下来就可以下载DPDK并运行rte_ring无锁环队列Demo应用,需要从

https://www.dpdk.org/

官网中下载DPDK 19.11.10 (LTS)长期支持版本:

aed037f6-6fd6-11ec-86cf-dac502259ad0.jpg

在根目录下的mk/文件夹下找到名为rte_vars.mk设置文件,找到环境变量RTE_KERNELDIR,修改为上述的内核源码路径:

aef06c42-6fd6-11ec-86cf-dac502259ad0.jpg

af1baf2e-6fd6-11ec-86cf-dac502259ad0.jpg

RTE_KERNELDIR ?= /home/OK8MP-linux-kernel/

进入usertools文件夹,找到dpdk-setup.sh脚本并运行

af50d12c-6fd6-11ec-86cf-dac502259ad0.jpg

afa77ef0-6fd6-11ec-86cf-dac502259ad0.jpg

选择8,ARM64-armv8a-linuxapp-gcc,

aff63860-6fd6-11ec-86cf-dac502259ad0.jpg

这个选项会使dpdk的gcc交叉编译链生成适用于armv8a处理器的外部库,外部库中有kmod和lib等ko文件和so文件,是用于第三方程序开发和运行的:

b02ae736-6fd6-11ec-86cf-dac502259ad0.jpg

b062a59a-6fd6-11ec-86cf-dac502259ad0.jpg

使用指令

insmod /home/dpdk-stable-19.11.10/arm64-armv8a-linuxapp-gcc/kmod/igb_uio.ko
左右滑动查看完整代码

加载igb_uio.ko驱动文件,这是进行dpdk开发必备的步骤:

b09bad04-6fd6-11ec-86cf-dac502259ad0.jpg

然后是使用dpdk-devbind.py脚本手动进行hugepage大页内存绑定,此处为numa方式:

b0c8c2ee-6fd6-11ec-86cf-dac502259ad0.jpg

此举会将/mnt/huge文件mount成hugepage映射文件,并实实在在地占用内存空间:

b104b54c-6fd6-11ec-86cf-dac502259ad0.jpg
b12e5848-6fd6-11ec-86cf-dac502259ad0.jpg

三、rte_ring无锁环队列

准备工作完成,我们接下来可以进行rte_ring无锁环队列Demo代码的编写,但是在编写之前,需要对无锁环队列有一个基本的认识:https://blog.csdn.net/chen98765432101/article/details/69367633


无论是dpdk第三方开发的rte_ring还是Linux内核中本就存在的无锁环队列,其基本原理类似,在一条分配好的队列型内存空间中,读写方式为FIFO(先进先出),读和写的动作分别有两个进程或两个线程进行,写进程不断往地址自增的内存位置写入数据,读进程不断读取地址自增的内存位置的数据,当写位置的内存地址已为队列中内存的最高值时,需要释放队列中内存地址最低值的空间供写进程继续写,方式仍与上一周期相同(不断往地址自增的内存位置写入数据),释放过程需要保证对末尾内存地址空间的锁定与解锁,避免读写过程出错。而不同的是,Linux内核中的无锁环队列,地址管理和读写控制均由内核进行,而dpdk的rte_ring则由dpdk内部的控制器进行,因为dpdk这一模块完整地接管了所分配内存空间的管理权,是直接绕过Linux内核进行管理的,内核也无权访问dpdk控制器的具体管理细节。

b166ff54-6fd6-11ec-86cf-dac502259ad0.jpg

b1bab982-6fd6-11ec-86cf-dac502259ad0.jpg

b1f20900-6fd6-11ec-86cf-dac502259ad0.jpg

b2256d7c-6fd6-11ec-86cf-dac502259ad0.jpg

编写无锁环队列两个进程的Demo,先写Primary进程:

#include #include #include #include #include #include #include #include #include #include 
#include #include 
#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
static const char *_MSG_POOL = "MSG_POOL";static const char *_SEC_2_PRI = "SEC_2_PRI";static const char *_PRI_2_SEC = "PRI_2_SEC";static const char *_PRI_2_THI = "PRI_2_THI";
struct rte_ring *send_ring, *recv_ring , *send_ring_third;struct rte_mempool *message_pool;volatile int quit = 0;
static void * lcore_recv(void *arg){        unsigned lcore_id = rte_lcore_id();
        printf("Starting core %u\n", lcore_id);        while (!quit){                void *msg;                if (rte_ring_dequeue(recv_ring, &msg) < 0)                {                        usleep(5);                        continue;                }                printf("lcore_id = %d Received '%s'\n" , lcore_id , (char *)msg);                rte_mempool_put(message_pool , msg);        }
        return 0;}
int string_size = 100;int elt_size = 128;pthread_t id1;
int main(int argc, char **argv){        const unsigned flags = 0;        const unsigned ring_size = 64;        const unsigned pool_size = 1024;        const unsigned pool_cache = 32;        const unsigned priv_data_sz = 0;
        int ret;        unsigned lcore_id;
        ret = rte_eal_init(argc, argv);        if (ret < 0)                rte_exit(EXIT_FAILURE, "Cannot init EAL\n");
        send_ring = rte_ring_create(_PRI_2_SEC, ring_size, rte_socket_id(), flags);        recv_ring = rte_ring_create(_SEC_2_PRI, ring_size, rte_socket_id(), flags);        send_ring_third = rte_ring_create(_PRI_2_THI, ring_size, rte_socket_id(), flags);        message_pool = rte_mempool_create(_MSG_POOL, pool_size,                        elt_size, pool_cache, priv_data_sz,                        NULL, NULL, NULL, NULL,                        rte_socket_id(), flags);
        if (send_ring == NULL)                rte_exit(EXIT_FAILURE, "Problem getting sending ring\n");
        if (recv_ring == NULL)                rte_exit(EXIT_FAILURE, "Problem getting receiving ring\n");
        if (send_ring_third == NULL)                rte_exit(EXIT_FAILURE, "Problem getting send_ring_third\n");
        if (message_pool == NULL)                rte_exit(EXIT_FAILURE, "Problem getting message pool\n");
        pthread_create(&id1 , NULL , lcore_recv , NULL);        while(1)        {                void *msg = NULL;                if (rte_mempool_get(message_pool, &msg) < 0)                        continue;
                snprintf((char *)msg, string_size, "%s", "primary to secondary");                if (rte_ring_enqueue(send_ring , msg) < 0)                 {                        rte_mempool_put(message_pool, msg);                }
                if (rte_mempool_get(message_pool, &msg) < 0)                        continue;
                snprintf((char *)msg, string_size, "%s", "primary to third");                if (rte_ring_enqueue(send_ring_third , msg) < 0)                 {                        rte_mempool_put(message_pool, msg);                }
                sleep(1);        }
        return 0;}
左右滑动查看完整代码

注意在Makefile文件里面要关闭WERROR相关编译选项:

#   BSD LICENSE##   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.#   All rights reserved.##   Redistribution and use in source and binary forms, with or without#   modification, are permitted provided that the following conditions#   are met:##     * Redistributions of source code must retain the above copyright#       notice, this list of conditions and the following disclaimer.#     * Redistributions in binary form must reproduce the above copyright#       notice, this list of conditions and the following disclaimer in#       the documentation and/or other materials provided with the#       distribution.#     * Neither the name of Intel Corporation nor the names of its#       contributors may be used to endorse or promote products derived#       from this software without specific prior written permission.##   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ifeq ($(RTE_SDK),)$(error "Please define RTE_SDK environment variable")endif
# Default target, can be overridden by command line or environmentRTE_TARGET ?= arm64-armv8a-linuxapp-gcc
include $(RTE_SDK)/mk/rte.vars.mk
# binary nameAPP = rte_ring_primary
# all source are stored in SRCS-ySRCS-y := main.c
CFLAGS += -O0CFLAGS += 
include $(RTE_SDK)/mk/rte.extapp.mk
左右滑动查看完整代码

Secondary进程:

#include #include #include #include #include #include #include #include #include #include 
#include #include 
#define RTE_LOGTYPE_APP RTE_LOGTYPE_USER1
static const char *_MSG_POOL = "MSG_POOL";static const char *_SEC_2_PRI = "SEC_2_PRI";static const char *_PRI_2_SEC = "PRI_2_SEC";
struct rte_ring *send_ring, *recv_ring;struct rte_mempool *message_pool;volatile int quit = 0;int string_size = 100;
static int lcore_send(__attribute__((unused)) void *arg){        unsigned lcore_id = rte_lcore_id();
        while(1)        {                void *msg = NULL;                if (rte_mempool_get(message_pool, &msg) < 0)                        continue;
                snprintf((char *)msg , string_size , "%s", "secondary to primary");                if (rte_ring_enqueue(send_ring , msg) < 0)                 {                        rte_mempool_put(message_pool, msg);                }                sleep(1);        }        return 0;}
pthread_t id1;
int main(int argc, char **argv){        const unsigned flags = 0;        const unsigned ring_size = 64;        const unsigned pool_size = 1024;        const unsigned pool_cache = 32;        const unsigned priv_data_sz = 0;
        int ret;        unsigned lcore_id;        ret = rte_eal_init(argc, argv);        if (ret < 0)                rte_exit(EXIT_FAILURE, "Cannot init EAL\n");
        recv_ring = rte_ring_lookup(_PRI_2_SEC);        send_ring = rte_ring_lookup(_SEC_2_PRI);        message_pool = rte_mempool_lookup(_MSG_POOL);
        if (send_ring == NULL)                rte_exit(EXIT_FAILURE, "Problem getting sending ring\n");        if (recv_ring == NULL)                rte_exit(EXIT_FAILURE, "Problem getting receiving ring\n");        if (message_pool == NULL)                rte_exit(EXIT_FAILURE, "Problem getting message pool\n");
        pthread_create(&id1 , NULL , lcore_send , NULL);    while (1)        {                lcore_id = rte_lcore_id();        void * msg = NULL;        if (rte_ring_dequeue(recv_ring, &msg) < 0)                {            usleep(5);            continue;        }
        printf("lcore_id = %d Received: %s\n" , lcore_id , (char *)msg);
        rte_mempool_put(message_pool, msg);    }
        return 0;}

左右滑动查看完整代码

同样在Makefile文件里面要关闭WERROR相关编译选项:

#   BSD LICENSE##   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.#   All rights reserved.##   Redistribution and use in source and binary forms, with or without#   modification, are permitted provided that the following conditions#   are met:##     * Redistributions of source code must retain the above copyright#       notice, this list of conditions and the following disclaimer.#     * Redistributions in binary form must reproduce the above copyright#       notice, this list of conditions and the following disclaimer in#       the documentation and/or other materials provided with the#       distribution.#     * Neither the name of Intel Corporation nor the names of its#       contributors may be used to endorse or promote products derived#       from this software without specific prior written permission.##   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ifeq ($(RTE_SDK),)$(error "Please define RTE_SDK environment variable")endif
# Default target, can be overridden by command line or environmentRTE_TARGET ?= arm64-armv8a-linuxapp-gcc
include $(RTE_SDK)/mk/rte.vars.mk
# binary nameAPP = rte_ring_secondary
# all source are stored in SRCS-ySRCS-y := main.c
CFLAGS += -O3CFLAGS += $()
include $(RTE_SDK)/mk/rte.extapp.mk
左右滑动查看完整代码

运行,这里说一下,基于rte_ring的进程间通信,Secondary进程最好是使用auto类型:

./rte_ring_primary --proc-type primary./rte_ring_secondary --proc-type auto

运行效果:

b254fb0a-6fd6-11ec-86cf-dac502259ad0.jpg

b2a99c3c-6fd6-11ec-86cf-dac502259ad0.jpg

作者简介

donatello1996,某大型企业资深嵌入式工程师,电子发烧友论坛技术大牛,同时也是飞凌嵌入式多年铁粉,曾基于飞凌多款板卡产出过优质测评文章或使用心得。本期三篇文章为donatello1996在使用OKMX8MP-C开发板过程中精心产出的干货,在此对donatello1996表示感谢。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5186

    文章

    20153

    浏览量

    328940
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    电子发烧友积分如何兑换奖励?

    电子发烧友积分如何兑换奖励?
    发表于 11-19 09:34

    [投票评选]2025电子发烧友开发板测评大赛--最受欢迎开发板

    2025电子发烧友开发板测评大赛--最受欢迎开发板 大赛详情: 电子发烧友携手 16 家生态厂商发起开发板测评大赛,设 OpenHarmony、RISC - V、Rockchip 三大赛道,共计
    发表于 10-13 16:25

    电子发烧友工程师看!电子领域评职称,技术之路更扎实

    ),这些提升不仅能帮咱们拿下职称,更能应对电子行业快速迭代的技术挑战。​ 电子发烧友的技术伙伴们,你们身边有没有靠职称实现职业跃迁的案例?或是在准备评电子、嵌入式、电源相关职称,想交流项目材料整理、评审答辩技巧?评论区一起聊聊,让我们用技术实力 + 职称认证,在电子行业走
    发表于 08-20 13:53

    新进发烧友

    今天注册成为了电子发烧友,多学习,多交流,多进步
    发表于 06-10 10:59

    电子发烧友积分能换什么?

    电子发烧友积分能换什么?
    发表于 06-10 05:55

    i.MX8MP使用最新的BSP (6.6.52-2.2.0) 映像安装TA失败,为什么?

    我正在为 i.MX8MP 测试最新的 BSP image(),发现在尝试安装 TA 时会出现以下错误 root@imx8mpevk:~# xtest --install-ta /usr/lib
    发表于 03-28 07:40

    将Deepseek移植到i.MX 8MP|93 EVK的步骤

    测试了不同模型对不同电路板的影响。需要注意的是,限制模型在电路板上运行的最大障碍是内存。包括 CPU 和内存使用情况在内的测试结果如下: a. i.MX8mp 深度搜索-r1-蒸馏
    发表于 03-26 06:08

    如何在IMX8MP上配置单通道内存?

    我正在使用 i.MX 8M Plus 评估套件。测试 2 通道 LPDDR4 设备很好。但是,配置 1 个通道 LPDDR4 很困难,因为根据原理图,i.MX8MP 侧的通道 A 连接到 LPDDR4 侧的通道 B。如何在此交换
    发表于 03-17 07:00

    电子发烧友荣获飞凌嵌入式“2024年度最具价值媒体”奖

    近日,飞凌嵌入式授予电子发烧友平台 “2024年度最具价值媒体”奖 ,以表彰其在过去一年中深度合作,为电子工程师、开发者及技术爱好者群体带来的卓越价值。此次授牌不仅是对电子发烧友平台的认可,更是双方
    发表于 02-28 15:20

    分享!基于NXP i.MX 8M Plus平台的OpenAMP核通信方案

    i.MX 8M Plus平台。 OpenAMP架构 AMP(Asymmetric Multi-Processing),即非对称多处理架构。“非对称AMP”双系统是指多个核心相对独立运行不同的操作系统或
    的头像 发表于 02-27 10:44 873次阅读
    分享!基于NXP <b class='flag-5'>i.MX</b> <b class='flag-5'>8</b>M Plus平台的OpenAMP核<b class='flag-5'>间</b><b class='flag-5'>通信</b>方案

    强悍的I.MX8MP核心板

    设计 I.MX8MP 核心板的尺寸仅为 30mmX38mm,如此小巧的身材,在空间有限的应用场景中具有得天独厚的优势。其采用 10 层 2 阶 PCB 设计,这种设计不仅保障了核心板的稳定性和可靠性,还在有限的空间内实现了高密度的电路布局,为丰富的功能集成奠定了基
    的头像 发表于 02-13 17:05 668次阅读

    [求职] RK3588核心板,寻找志同道合的电子发烧友

    实现数据本地化处理和实时分析。 自我评价 我是一款功能强大、性能卓越的核心板,拥有丰富的接口和强大的扩展能力,能够满足各种应用场景的需求。我热爱挑战,乐于学习新技术,期待与各位电子发烧友一起探索
    发表于 02-11 10:49

    电子发烧友社区2025年春节放假通知!

    尊敬的电子发烧友用户及各位工程师: 新春佳节将至,电子发烧友全体员工提前祝大家新年快乐,阖家幸福,事业蒸蒸日上!感谢大家在过去一年里的支持与陪伴,愿我们在新的一年里继续携手共进,共同探索科技的无限
    发表于 01-22 13:42

    榜样力量,智领未来——2024年度电子发烧友社区表彰

    2024 年里,电子发烧友汇聚了超过670万名用户,他们在这里分享、学习并探索最新的技术内容。 这一年,电子发烧友平台累计产生超过120000篇文章、36000篇帖子、21000个资料、22000个
    发表于 01-16 13:36

    面向NXP i.MX8处理器的电源解决方案

    电子发烧友网站提供《面向NXP i.MX8处理器的电源解决方案.pdf》资料免费下载
    发表于 12-24 15:53 0次下载
    面向NXP <b class='flag-5'>i.MX8</b>处理器的电源解决方案