hugetlbfs
CPU缓存中有一组缓存专门用于缓存TLB,但其大小是有限的。当采用的默认页面大小为 4KB,其产生的TLB较大,因而将会产生较多 TLB Miss 和缺页中断,从而大大影响应用程序的性能。操作系统以 2MB 甚至更大作为分页的单位时,将会大大减少 TLB Miss 和缺页中断的数量,显著提高应用程序的性能。这也正是 Linux 内核引入大页面支持的直接原因。好处是很明显的,假设应用程序需要 2MB 的内存,如果操作系统以 4KB 作为分页的单位,则需要 512 个页面,进而在 TLB 中需要 512 个表项,同时也需要 512 个页表项,操作系统需要经历至少 512 次 TLB Miss 和 512 次缺页中断才能将 2MB 应用程序空间全部映射到物理内存;然而,当操作系统采用 2MB 作为分页的基本单位时,只需要一次 TLB Miss 和一次缺页中断,就可以为 2MB 的应用程序空间建立虚实映射,并在运行过程中无需再经历 TLB Miss 和缺页中断(假设未发生 TLB 项替换和 Swap)。
为了能以最小的代价实现大页面支持,Linux 操作系统采用了基于 hugetlbfs 特殊文件系统 2M 字节大页面支持。这种采用特殊文件系统形式支持大页面的方式,使得应用程序可以根据需要灵活地选择虚存页面大小,而不会被强制使用 2MB 大页面。
使用
使用巨页需要在内核编译的时候打开相关的配置选项:CONFIG_HUGETLBFS, CONFIG_HUGETLB_PAGE
命令 cat /proc/filesystems 还应该显示配置的“hugetlbfs”类型的文件系统在内核中。
命令 cat /proc/sys/vm/
表示当前配置的hugetlb数量内核中的页面。超级用户可以动态请求更多(或释放一些预配置)大页面。
也可通过命令 grep Huge /proc/meminfo
查看
可以通过命令sudo sysctl vm.nr_hugepages=192
修改巨页的数量为192页。
内核编译完成并成功启动内核之后,将 hugetlbfs 特殊文件系统挂载到根文件系统的某个目录上去,以使得 hugetlbfs 可以访问。命令如下:
mount none /mnt/huge -t hugetlbfs
此后,只要是在 /mnt/huge/ 目录下创建的文件,将其映射到内存中时都会使用 2MB 作为分页的基本单位。值得一提的是,hugetlbfs 中的文件是不支持读 / 写系统调用 ( 如read()或write()等 ) 的,一般对它的访问都是以内存映射的形式进行的。
测试代码
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include<string.h>
#define MAP_LENGTH (10*1024*1024)
int main()
{
int fd;
void * addr;
/* create a file in hugetlb fs */
fd = open("/mnt/huge/test", O_CREAT | O_RDWR);
if(fd < 0){
perror("Err: ");
return -1;
}
/* map the file into address space of current application process */
addr = mmap(0, MAP_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED){
perror("Err: ");
close(fd);
unlink("/mnt/huge/test");
return -1;
}
/* from now on, you can store application data on huage pages via addr */
memset(addr,0,MAP_LENGTH);
getchar();
munmap(addr, MAP_LENGTH);
close(fd);
unlink("/mnt/huge/test");
return 0;
}
2.在权限上做了处理,其实都是通过mmap系统调用
#include <sys/mman.h>