dpdk secondary 进程与 primary 进程同步失败问题分析

本文探讨了在DPDK环境中,primary进程主动申请大页内存并同步给secondary进程时,两者行为的差异。主要关注内存同步失败导致的问题,以及primary和secondary进程各自的内存申请逻辑和处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测试版本

dpdk-19.11

primary 进程主动申请内存的用例

primary 进程修改

以 l2fwd 为 primary 进程,在 dpdk 初始化完成后增加如下调用:

sleep(20);
void *ptr = rte_malloc(NULL, 209715200, RTE_CACHE_LINE_SIZE);

测试过程

primary 进程启动后延时 20s 后分配大量的内存,需要超过 100 个大页数目,secondary 进程设置 ulimit -n 为 100,在 20s 内运行。

primary 进程运行相关打印

EAL: Secondary process failed to synchronize
alloc ptr 0x400001e00000

primary 进程打印了 secondary 进程同步失败的错误,内存申请是成功的。从结果看,primary 进程

secondary 进程运行相关打印

EAL: rte_mem_virt2phy(): cannot open /proc/self/pagemap: Too many open files

secondary 进程由于 ulimit 限制,内存同步失败,不能同步 primary 进程的大页内存。

secondary 进程主动申请内存的用例

secondary 进程修改

以 dpdk-procinfo 为 secondary 进程,在 dpdk 初始化完成后增加如下调用:

sleep(20);
void *ptr = rte_malloc(NULL, 209715200, RTE_CACHE_LINE_SIZE);

printf("ptr is %p\n", ptr);

并增加 while 循环,持续 sleep 常驻。

测试过程

  1. 运行未修改的 l2fwd 程序
  2. 设置 ulimit -n 为 100,启动 dpdk-procinfo 进程

测试结果

dpdk-procinfo 进程报了 Too man open files 的错误,申请内存为空,ptr 指针的值为空。

为什么在 secondary 进程中跟 primary 进程中申请内存表现不同?

在 primary 进程中申请大页内存的主要逻辑

  1. rte_malloc 内部函数调用逻辑判断现有的大小能否满足,不满足则需要动态映射更多的大页扩充 heap
  2. try_expand_heap 子函数调用负责映射大页并扩充 heap,判断到是 primary 进程,调用 try_expand_heap_primary 函数
  3. try_expand_heap_primary 函数根据传入参数映射新的大页并更新内部数据结构,在映射完成后通过 unix 本地套接字发 mp_malloc_sync 消息给每个 secondary 进程同步内存并等待回复消息
  4. 当有 secondary 进程回复失败消息后,跳过失败,向上返回

当 primary 进程分配内存成功,secondary 进程同步失败时,内存分配仍旧成功。

在 secondary 进程中申请大页内存的主要逻辑

  1. rte_malloc 内部函数调用逻辑判断现有的大小能否满足,不满足则需要动态映射更多的大页扩充 heap
  2. try_expand_heap 子函数调用负责映射大页并扩充 heap,判断到是 primary 进程,调用 try_expand_heap_secondary 函数
  3. try_expand_heap_secondary 函数构造 mp_malloc_request 请求发送到 primary 进程中
  4. primary 进程接收到 mp_malloc_request 消息后,调用回调函数完成所有的大页内存映射后,失败则构造 mp_malloc_response 回复失败的结果,成功则构造 mp_malloc_sync 请求发送到 secondary 进程同步内存信息
  5. secondary 进程收到 mp_malloc_sync 消息后,更新大页,构造 mp_malloc_sync 消息与执行成功的状态发往 primary 进程
  6. primary 进程收到 handle_sync_response 回复消息后,查看成功状态,存在失败则执行 rollback 动作,然后构造 mp_malloc_rollback 消息发到 secondary 进程
  7. secondary 进程收到 mp_malloc_rollback 消息后,执行回调并回复一条 mp_malloc_rollback 消息,并附带执行的结果
  8. primary 进程收到 mp_malloc_rollback 消息,构造 mp_malloc_response 消息发送给 secondary 进程标示内存申请结束

当 primary 进程分配内存成功,secondary 进程同步失败时,内存分配 rollback,分配失败。

### DPDK进程源码分析 DPDK(Data Plane Development Kit)是一个高性能的数据平面开发工具包,主要用于加速网络应用中的数据包处理。其多进程支持允许多个独立的DPDK进程协同工作以完成特定的任务[^2]。 #### EAL初始化过程 在DPDK中,多进程的支持主要依赖于EAL(Environment Abstraction Layer)。当启动一个多进程程序时,EAL会负责初始化共享内存区域以及同步机制。这些资源对于不同进程之间的通信至关重要。具体来说,在`rte_eal_init()`函数内部实现了对共享内存段的创建和映射操作。 ```c int rte_eal_init(int argc, char **argv); ``` 该函数不仅解析命令行参数还完成了如下几项重要任务: - 设置全局变量`internal_config->process_type`表示当前运行的是主进程还是次级进程。 - 如果检测到已有其他实例存在,则尝试连接已有的共享内存池;否则新建一个新池子供后续加入者使用。 #### 进程间同步资源共享 为了实现高效而安全的跨进程访问控制,DPDK引入了几种不同的锁原语用于保护临界区代码片段免受竞争条件影响: 1. 自旋锁(`rte_spinlock_t`):适用于短时间锁定场景下减少上下文切换开销; 2. 互斥量(`pthread_mutex_t`)封装版本——即所谓的公平性更好的读写锁方案之一; 3. 原子计数器类APIs如`rte_atomic*_*()`系列宏定义提供了细粒度级别的并发管理能力[^3]。 以下是关于如何利用上述提到的技术构建实际应用程序的一个简单例子展示: ```c #include <rte_common.h> #include <rte_lcore.h> #include <rte_ring.h> struct my_shared_data { struct rte_ring *ring; }; /* Assume this function is called by secondary process */ void init_secondary(struct my_shared_data *data){ data->ring = rte_ring_lookup("my_rings"); } // Primary Process Code Snippet... if (rte_eal_process_type() == RTE_PROC_PRIMARY) { struct my_shared_data pdata; pdata.ring = rte_ring_create("my_rings", 1024, SOCKET_ID_ANY,RING_F_SP_ENQ|RING_F_SC_DEQ); } ``` 通过以上示范可以看出,无论是初级还是辅助角色都能轻松获取预先分配好的环形缓冲队列对象来进行消息传递等活动。 #### 总结 综上所述,DPDK 的多进程特性极地增强了系统的灵活性和可扩展性。通过对底层基础设施的有效管理和合理设计接口协议,使得开发者可以更加专注于业务逻辑本身而不必担心复杂的线程调度或者分布式计算带来的额外负担。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值