树莓派4 64位系统HugePages管理及mmap使用技术求助
首先得指出你代码里的一个关键错误:mmap的参数顺序不对!你写的:
mem = mmap(NULL,buf_size,PROT_READ|PROT_WRITE,MAP_SHARED,MAP_HUGETLB,fd,0);
这里把MAP_HUGETLB当成了第四个参数之后的独立参数,但实际上mmap的第四个参数flags需要把所有标志位用位或(|)组合起来,正确的写法应该是:
mem = mmap(NULL, buf_size, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_HUGETLB, fd, 0);
不过别急,就算修正了参数,你当前的内核配置可能还没法用MAP_HUGETLB,咱们一步步分析:
1. 透明大页(THP) vs 显式HugeTLB大页的区别
你已经启用了透明大页(从/sys/kernel/mm/transparent_hugepage/enabled的[always]和/proc/meminfo里的AnonHugePages数值可以确认),而且内核配置CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y意味着内核会自动尝试把符合条件的匿名映射合并成大页,不需要你在mmap里加额外标志。
而MAP_HUGETLB是用来申请显式大页的,这依赖于内核的CONFIG_HUGETLB_PAGE和CONFIG_HUGETLBFS配置——但你的内核里# CONFIG_HUGETLBFS is not set,甚至没提到CONFIG_HUGETLB_PAGE是否开启,这意味着显式大页的支持是缺失的,直接用MAP_HUGETLB会导致mmap返回MAP_FAILED。
2. 针对你“映射最大连续内存块”的需求
如果你的映射是匿名映射(也就是fd=-1,配合MAP_ANONYMOUS标志),那么当前的透明大页已经在帮你工作了:内核会自动把连续的小页合并成2MB的大页(树莓派4的大页默认大小是2MB),你不需要修改原mmap代码,就能享受到大页的好处。
如果你的映射是文件映射(你代码里传了fd),那需要注意两点:
- 你的
FileHugePages为0,可能是因为文件没有按大页大小(2MB)对齐,或者文件系统不支持透明大页缓存。你可以先把文件的大小调整为2MB的整数倍,并且确保文件偏移量也是2MB对齐的。 - 可以配合
madvise函数给内核提示,让它优先用大页缓存:madvise(mem, buf_size, MADV_HUGEPAGE);
3. 如果一定要用显式HugeTLB大页
如果你确实需要显式控制大页分配,那得重新编译内核:
- 开启
CONFIG_HUGETLB_PAGE和CONFIG_HUGETLBFS选项 - 编译完成后,挂载hugetlbfs文件系统:
之后再用修正后的mount -t hugetlbfs hugetlbfs /dev/hugepagesMAP_SHARED | MAP_HUGETLB标志调用mmap(如果是匿名显式大页,还需要加上MAP_ANONYMOUS,并且fd=-1)。
内容的提问来源于stack exchange,提问作者user13938059

