2. 大页内存配置与验证
任务目标
本案例目标是在Linux系统上配置大页内存(HugePages),使DPDK能够正确识别并使用大页,同时通过DPDK内存池(mempool)的创建来验证大页配置是否生效。
环境与依赖
- Linux系统(建议内核 ≥ 3.8,x86_64架构)
- DPDK库(版本 ≥ 20.11,本案例使用DPDK 22.11验证)
- GCC编译器、libnuma-dev(可选,用于NUMA感知)
- root权限(配置大页需要)
大页配置步骤
首先,在系统启动时预留大页内存。编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中添加:
default_hugepagesz=1G hugepagesz=1G hugepages=4
然后更新GRUB并重启系统:
sudo update-grub
sudo reboot
重启后,验证大页是否成功预留:
grep Huge /proc/meminfo
预期输出(示例):
HugePages_Total: 4
HugePages_Free: 4
Hugepagesize: 1048576 kB
如果系统不支持1G大页,可以使用2M大页作为替代:
default_hugepagesz=2M hugepagesz=2M hugepages=1024
DPDK大页挂载与配置
DPDK运行时需要访问大页文件系统。执行以下命令挂载hugetlbfs并设置DPDK环境变量:
sudo mkdir -p /mnt/huge
sudo mount -t hugetlbfs pagesize=1G /mnt/huge
echo 4 | sudo tee /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages
如果使用2M大页,挂载命令为:
sudo mount -t hugetlbfs pagesize=2M /mnt/huge
完整代码:DPDK大页验证程序
以下代码初始化DPDK EAL环境,创建内存池并输出大页使用信息:
#include <rte_eal.h>
#include <rte_mempool.h>
#include <rte_memory.h>
#include <stdio.h>
#include <stdint.h>
#define MEMPOOL_SIZE 8192
#define CACHE_SIZE 256
int main(int argc, char **argv) {
int ret;
struct rte_mempool *mp;
unsigned int i;
const struct rte_memseg *ms;
uint64_t huge_total = 0, huge_used = 0;
/* 初始化EAL,必须传入 --huge-dir 或使用默认挂载点 */
ret = rte_eal_init(argc, argv);
if (ret < 0) {
printf("EAL初始化失败: %d\n", ret);
return -1;
}
/* 遍历所有内存段,统计大页使用情况 */
for (i = 0; i < rte_memory_get_nmemsegs(); i++) {
ms = rte_memseg_get(i);
if (ms == NULL) continue;
huge_total += ms->len;
if (ms->state == RTE_MEMSEG_IN_USE)
huge_used += ms->len;
}
printf("DPDK检测到大页内存总量: %lu MB\n", huge_total / (1024*1024));
printf("已使用大页内存: %lu MB\n", huge_used / (1024*1024));
/* 创建内存池,验证大页分配 */
mp = rte_mempool_create("test_pool", MEMPOOL_SIZE,
RTE_MBUF_DEFAULT_BUF_SIZE, CACHE_SIZE,
0, NULL, NULL, NULL, NULL,
SOCKET_ID_ANY, 0);
if (mp == NULL) {
printf("内存池创建失败: %s\n", rte_strerror(rte_errno));
rte_eal_cleanup();
return -1;
}
printf("内存池创建成功: %s\n", mp->name);
printf("内存池对象数: %u\n", rte_mempool_avail_count(mp));
printf("内存池大小: %zu bytes\n", rte_mempool_mem_size(mp));
/* 验证内存池内存是否来自大页 */
struct rte_mempool_memhdr *memhdr;
int hugepage_count = 0;
STAILQ_FOREACH(memhdr, &mp->mem_list, next) {
if (memhdr->hugepage_sz > 0) {
hugepage_count++;
printf("内存块 %d: 大页大小 %lu KB\n",
hugepage_count, memhdr->hugepage_sz / 1024);
}
}
if (hugepage_count == 0) {
printf("警告: 内存池未使用大页!\n");
} else {
printf("验证通过: 内存池使用 %d 个大页内存块\n", hugepage_count);
}
/* 释放资源 */
rte_mempool_free(mp);
rte_eal_cleanup();
return 0;
}
编译与运行
使用pkg-config编译:
gcc -o hugepage_test hugepage_test.c $(pkg-config --cflags --libs libdpdk)
运行程序(需要root权限):
sudo ./hugepage_test --huge-dir=/mnt/huge
验证方法与判定标准
程序运行后,观察以下输出以确认大页配置成功:
- 大页总量检测:程序输出的“DPDK检测到大页内存总量”应大于0,且数值与系统配置的大页总量一致(例如配置4个1G大页,则总量约为4096 MB)。
- 内存池创建:输出“内存池创建成功”且对象数为8192,说明DPDK成功从大页分配内存。
- 大页使用确认:输出“验证通过: 内存池使用 N 个大页内存块”,N ≥ 1,证明内存池内存确实来自大页。
如果程序输出“内存池创建失败”或“警告: 内存池未使用大页”,请检查:
- 大页是否成功预留(
cat /proc/meminfo查看HugePages_Free) - hugetlbfs是否正确挂载到
/mnt/huge - EAL参数是否正确指定
--huge-dir
常见问题
- EAL初始化失败:通常是因为没有root权限或大页目录不可访问。使用
sudo运行,并确认/mnt/huge存在且已挂载。 - 内存池创建失败(ENOMEM):大页内存不足。增加系统大页数量或减小
MEMPOOL_SIZE。 - NUMA节点问题:如果系统有多个NUMA节点,确保每个节点都有足够大页,或使用
--socket-mem指定内存分配。