3. 内存池创建与对象分配
任务目标
使用DPDK的rte_mempool_create创建内存池,从池中分配/释放rte_mbuf结构,验证内存池的统计计数变化,理解DPDK内存池的无锁环形缓冲区管理机制。
环境依赖
DPDK已编译并绑定igb_uio或vfio-pci驱动,具备hugepages(建议2MB页,至少64MB)。编译需链接-lrte_mempool -lrte_mbuf -lrte_eal。
核心实现
#include <rte_mempool.h>
#include <rte_mbuf.h>
#include <rte_eal.h>
#include <stdio.h>
#define POOL_SIZE 4096
#define CACHE_SIZE 256
#define BUF_SIZE 2048
int main(int argc, char **argv) {
// 初始化EAL(需传入--file-prefix等参数)
int ret = rte_eal_init(argc, argv);
if (ret < 0) {
printf("EAL init failed: %d\n", ret);
return -1;
}
// 1. 创建内存池:每个对象为mbuf + 私有数据区
struct rte_mempool *mp = rte_mempool_create(
"my_pool", // 池名称
POOL_SIZE, // 对象数量(含per-lcore缓存)
BUF_SIZE, // 每个对象大小(含mbuf头)
CACHE_SIZE, // per-lcore缓存大小
sizeof(struct rte_pktmbuf_pool_private), // 私有数据区
rte_pktmbuf_pool_init, // 池初始化回调
NULL,
rte_pktmbuf_init, // mbuf初始化回调
NULL,
rte_socket_id(), // 在本地NUMA节点分配
0); // 无额外标志
if (mp == NULL) {
printf("mempool create failed\n");
return -1;
}
printf("Pool created: %s, objects=%u, size=%u\n",
mp->name, mp->size, mp->elt_size);
// 2. 从池中分配一个mbuf
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(mp);
if (mbuf == NULL) {
printf("mbuf alloc failed\n");
return -1;
}
printf("Allocated mbuf: pool=%s, buf_addr=%p, data_len=%u\n",
mbuf->pool->name, mbuf->buf_addr, mbuf->data_len);
// 3. 写入数据并调整长度
char *data = rte_pktmbuf_append(mbuf, 64);
if (data == NULL) {
printf("append failed\n");
return -1;
}
snprintf(data, 64, "DPDK mempool test");
printf("Data written: %s\n", rte_pktmbuf_mtod(mbuf, char *));
// 4. 释放mbuf回池
rte_pktmbuf_free(mbuf);
printf("mbuf freed back to pool\n");
// 5. 验证池统计(需编译时开启CONFIG_RTE_MEMPOOL_STATS)
printf("Pool stats: allocated_objs=%u, in_pool=%u\n",
rte_mempool_avail_count(mp), // 当前可用对象数
rte_mempool_in_use_count(mp)); // 已分配对象数
// 清理
rte_mempool_free(mp);
rte_eal_cleanup();
return 0;
}
编译与运行
# 编译(假设DPDK已安装到/usr/local)
gcc -o mempool_demo mempool_demo.c \
$(pkg-config --cflags --libs libdpdk) \
-lrte_mempool -lrte_mbuf -lrte_eal
# 运行(需root权限,指定hugepage内存)
sudo ./mempool_demo --file-prefix=pg --huge-dir=/mnt/huge \
-m 64 --no-pci
验证方法
程序正常输出以下内容即通过:
Pool created: my_pool, objects=4096, size=2176
Allocated mbuf: pool=my_pool, buf_addr=0x7f..., data_len=0
Data written: DPDK mempool test
mbuf freed back to pool
Pool stats: allocated_objs=4095, in_pool=1
关键判定点:
- 池创建成功:
objects=4096,且elt_size大于BUF_SIZE(因含mbuf头结构); - 分配/释放闭环:分配后
in_pool=1,释放后avail_count恢复为4095(因per-lcore缓存中仍有对象); - 数据写入正确:读取到
DPDK mempool test字符串。
内存池管理机制说明
DPDK内存池基于无锁环形队列(rte_ring)实现,每个核访问自己的per-lcore cache(大小为CACHE_SIZE)以减少锁竞争。分配时优先从本地缓存取对象,缓存不足时从全局池批量获取;释放时先放回本地缓存,缓存满后批量归还全局池。上述输出中avail_count=4095而非4096,是因为释放的mbuf进入了当前核的缓存而非立即回到全局池,这正是缓存机制的正常表现。
常见问题
- EAL初始化失败:确认hugepage已挂载且
--huge-dir路径正确,或改用--socket-mem指定内存; - 池创建返回NULL:检查
POOL_SIZE是否超过hugepage可用内存,或BUF_SIZE是否过小(需大于sizeof(struct rte_mbuf)); - 统计计数不变化:需在DPDK编译配置中开启
CONFIG_RTE_MEMPOOL_STATS=y,否则avail_count仍可用但in_use_count恒为0。