0%

Linux巨页的使用

普通巨页的内核说明文档在linux/Documentation/admin-guide/mm/hugetlbpage.rst

使用巨页需要在内核编译的时候打开相关的配置选项:CONFIG_HUGETLBFS, CONFIG_HUGETLB_PAGE

使能系统的巨页可以通过内核的启动参数或者是/sys/kernel/mm/hugepages/下的文件。
我们具体看下sysfs下的相关目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
hugepages/
├── hugepages-1048576kB
│   ├── free_hugepages
│   ├── nr_hugepages
│   ├── nr_hugepages_mempolicy
│   ├── nr_overcommit_hugepages
│   ├── resv_hugepages
│   └── surplus_hugepages
├── hugepages-2048kB
│   ├── free_hugepages
│   ├── nr_hugepages
│   ├── nr_hugepages_mempolicy
│   ├── nr_overcommit_hugepages
│   ├── resv_hugepages
│   └── surplus_hugepages
├── hugepages-32768kB
│   ├── free_hugepages
│   ├── nr_hugepages
│   ├── nr_hugepages_mempolicy
│   ├── nr_overcommit_hugepages
│   ├── resv_hugepages
│   └── surplus_hugepages
└── hugepages-64kB
├── free_hugepages
├── nr_hugepages
├── nr_hugepages_mempolicy
── nr_overcommit_hugepages
├── resv_hugepages
└── surplus_hugepages

可以看到在hugepages目录下为每个巨页大小都开了专门的目录。可以看到在我的ARM64
系统上,巨页有64KB,32KB,2MB,1GB四种类型。向nr_hugepages写数值可以创建指定数目
的巨页,读free_hugepages可以得到还没有使用的巨页数目。

一般巨页属于系统配置,我们只去使用,不去更改配置。使用的方法是在mmap的时候在
flags参数中加上MAP_HUGETLB。如果只用MAP_HUGETLB,巨页的分配算法是内核里定的,
比如,你要mmap 128KB的内存,在64KB和2MB都可以满足的时候,我们希望从64KB里搞两
页出来就好了,内核可能是从2MB里分配的,实际上,用5.10-rc2的内核,真的是从2MB的
页里分一页出来。

所以,针对巨页,mmap flags里还有宏可以指定从哪种大小的页里分巨页。man mmap下有:
MAP_HUGE_2MB, MAP_HUGE_1GB,不过直接用这个宏会报没有定义,这个是因为gcc版本比较
低,我们可以直接找见内核里定义的地方: linux/include/uapi/linux/mman.h

1
2
3
4
5
6
7
#define MAP_HUGE_64KB	HUGETLB_FLAG_ENCODE_64KB
#define MAP_HUGE_2MB HUGETLB_FLAG_ENCODE_2MB

#define HUGETLB_FLAG_ENCODE_64KB (16 << HUGETLB_FLAG_ENCODE_SHIFT)
#define HUGETLB_FLAG_ENCODE_2MB (21 << HUGETLB_FLAG_ENCODE_SHIFT)

#define HUGETLB_FLAG_ENCODE_SHIFT 26

可以看到16, 21正好是页大小以2为底的对数。所以,举个例子,我们可以如下指定从
64KB的巨页中申请内存:

1
2
3
4
5
6
7
8
9
10
int len = 128 * 1024;
unsigned long *p;
int i;

p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS |
MAP_HUGETLB | (16 << 26), -1, 0);

for (i = 0; i < len / sizeof(*p); i++) {
*(p + i) = 20;
}

之后再去看/sys/kernel/mm/hugepages/hugepages-64kB/free_hugepages, 会发现减少了2。
需要注意的是,mmap到的内存要去写下,内存才会真实分配,如果在mmap之后就去看
free_hugepages的值,其中还是原来的值。