huge page
[root@localhost ~]# free -g
total used free shared buff/cache available
Mem: 510 129 377 0 3 339
Swap: 0 0 0
[root@localhost ~]# cat /proc/meminfo | grep -i huge
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
HugePages_Total: 256
HugePages_Free: 255
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 524288 kB
#include <sys/mman.h> #include <stdio.h> #include <memory.h> int main(int argc, char *argv[]) { char *m; size_t s = (8UL * 1024 * 1024); m = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | 0x40000 /*MAP_HUGETLB*/, -1, 0); if (m == MAP_FAILED) { perror("map mem"); m = NULL; return 1; } memset(m, 0, s); printf("map_hugetlb ok, press ENTER to quit!\n"); getchar(); munmap(m, s); return 0; }
[root@localhost ~]# cat /proc/meminfo | grep -i huge AnonHugePages: 0 kB ShmemHugePages: 0 kB HugePages_Total: 256 HugePages_Free: 254 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 524288 kB [root@localhost ~]# free -g total used free shared buff/cache available Mem: 510 129 377 0 3 339 Swap:
[root@localhost ~]# ps -elf | grep map 0 S root 115112 114967 0 80 0 - 8231 wait_w 07:26 pts/0 00:00:00 ./map 0 S root 115141 115051 0 80 0 - 1729 pipe_w 07:26 pts/1 00:00:00 grep --color=auto map [root@localhost ~]# cat /proc/115112/map map_files/ maps [root@localhost ~]# cat /proc/115112/maps 00400000-00410000 r-xp 00000000 08:10 22155957 /data1/dpdk-19.11/demo/huge/map 00410000-00420000 r--p 00000000 08:10 22155957 /data1/dpdk-19.11/demo/huge/map 00420000-00430000 rw-p 00010000 08:10 22155957 /data1/dpdk-19.11/demo/huge/map 400000000000-400020000000 rw-p 00000000 00:0f 293434 /anon_hugepage (deleted) ffff9c9e0000-ffff9c9f0000 rw-p 00000000 00:00 0 ffff9c9f0000-ffff9cb60000 r-xp 00000000 08:03 247 /usr/lib64/libc-2.17.so ffff9cb60000-ffff9cb70000 r--p 00160000 08:03 247 /usr/lib64/libc-2.17.so ffff9cb70000-ffff9cb80000 rw-p 00170000 08:03 247 /usr/lib64/libc-2.17.so ffff9cb80000-ffff9cb90000 rw-p 00000000 00:00 0 ffff9cb90000-ffff9cba0000 r--p 00000000 00:00 0 [vvar] ffff9cba0000-ffff9cbb0000 r-xp 00000000 00:00 0 [vdso] ffff9cbb0000-ffff9cbd0000 r-xp 00000000 08:03 240 /usr/lib64/ld-2.17.so ffff9cbd0000-ffff9cbe0000 r--p 00010000 08:03 240 /usr/lib64/ld-2.17.so ffff9cbe0000-ffff9cbf0000 rw-p 00020000 08:03 240 /usr/lib64/ld-2.17.so fffff7cf0000-fffff7d20000 rw-p 00000000 00:00 0 [stack] [root@localhost ~]#
#include <sys/mman.h> #include <stdio.h> #include <memory.h> int main(int argc, char *argv[]) { char *m; size_t s = (16UL * 1024 * 1024*1024); //改大 m = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | 0x40000 /*MAP_HUGETLB*/, -1, 0); if (m == MAP_FAILED) { perror("map mem"); m = NULL; return 1; } memset(m, 0, s); printf("map_hugetlb ok, press ENTER to quit!\n"); getchar(); munmap(m, s); return 0; }
[root@localhost ~]# ps -elf | grep map 0 S root 115761 114967 21 80 0 - 262183 wait_w 07:39 pts/0 00:00:01 ./map 0 S root 115769 115051 0 80 0 - 1729 pipe_w 07:39 pts/1 00:00:00 grep --color=auto map [root@localhost ~]# cat /proc/meminfo | grep -i huge AnonHugePages: 0 kB ShmemHugePages: 0 kB HugePages_Total: 256 HugePages_Free: 223 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 524288 kB [root@localhost ~]# cat /proc/115761/maps 00400000-00410000 r-xp 00000000 08:10 22155957 /data1/dpdk-19.11/demo/huge/map 00410000-00420000 r--p 00000000 08:10 22155957 /data1/dpdk-19.11/demo/huge/map 00420000-00430000 rw-p 00010000 08:10 22155957 /data1/dpdk-19.11/demo/huge/map 400000000000-400400000000 rw-p 00000000 00:0f 292814 /anon_hugepage (deleted) ffffb1060000-ffffb1070000 rw-p 00000000 00:00 0 ffffb1070000-ffffb11e0000 r-xp 00000000 08:03 247 /usr/lib64/libc-2.17.so ffffb11e0000-ffffb11f0000 r--p 00160000 08:03 247 /usr/lib64/libc-2.17.so ffffb11f0000-ffffb1200000 rw-p 00170000 08:03 247 /usr/lib64/libc-2.17.so ffffb1200000-ffffb1210000 rw-p 00000000 00:00 0 ffffb1210000-ffffb1220000 r--p 00000000 00:00 0 [vvar] ffffb1220000-ffffb1230000 r-xp 00000000 00:00 0 [vdso] ffffb1230000-ffffb1250000 r-xp 00000000 08:03 240 /usr/lib64/ld-2.17.so ffffb1250000-ffffb1260000 r--p 00010000 08:03 240 /usr/lib64/ld-2.17.so ffffb1260000-ffffb1270000 rw-p 00020000 08:03 240 /usr/lib64/ld-2.17.so ffffffc30000-ffffffc60000 rw-p 00000000 00:00 0 [stack] [root@localhost ~]# free -g total used free shared buff/cache available Mem: 510 129 377 0 3 339 Swap: 0 0 0 [root@localhost ~]#
Linux中hugepage的使用方法
Linux中hugepage的使用方法#
Linux中使用hugepage有两种方法,分别是
- hugetlb
- transparent huge page (THP)
其中,hugetlb基于显式分配并保留的大页,而THP按需将内存转换成大页,无需提前保留,提供更加灵活、对系统其他部分影响更小的大页使用方式。
Hugetlb使用方法#
分配大页
-
默认size大页
echo N > /proc/sys/vm/nr_hugepages
将试图分配N个大页,页面大小是默认的(一般是2MB)。如果原来保留的页面个数大于N,那么将会释放多出来的页面。如果连续内存不够将保留页面数上升到N,则尽最大努力分配。cat /proc/sys/vm/nr_hugepages
可以查看保留页面个数。 -
在指定的NUMA结点试图分配N个指定页面大小的hugepage,修改或读取文件:
/sys/devices/system/node/node<node_id>/hugepages/hugepages-<page_size>/nr_hugepages
-
NUMA结点无关的指定页面大小的hugepage:
/sys/kernel/mm/hugepages/hugepages-1048576kB/
。如果直接写该文件来提升页面个数,将重复依次在各个NUMA结点试图分配一个页面(node0, node1, node2, node3, ..., node0, node1, node2, node3, ...)直到满足或不可进一步分配,例如:- 在每个node资源充足的情况下,将均匀分配页面到各个node。
- 若只有一个node可以分配大页,则大页全部分配到该node上。
- 若所有node可分配大页的内存总量之和仍不能满足N,则每个node尽最大努力分配大页。
使用大页
这里仅介绍mmap使用大页的方法。
在mmap的flag中添加MAP_HUGETLB
和<MAP_HUGE>。其中,<MAP_HUGE>为((N & MAP_HUGE_MASK) << MAP_HUGE_SHIFT)
,MAP_HUGE_MASK == 0x3f == 0b111111
,MAP_HUGE_SHIFT == 26
,N
为大页size的log2(来源:When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size.)
实例:
void *myMalloc1GbPage(size_t size) {
int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB |
((30 & MAP_HUGE_MASK) << MAP_HUGE_SHIFT); // 2^30 == 1G
int protection = PROT_READ | PROT_WRITE;
return mmap(NULL, size, protection, flags, -1, 0);
}
void *myMalloc2MbPage(size_t size) {
int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB |
((21 & MAP_HUGE_MASK) << MAP_HUGE_SHIFT); // 2^21 == 2M
int protection = PROT_READ | PROT_WRITE;
return mmap(NULL, size, protection, flags, -1, 0);
}
Transparent Huge Page#
分配大页
不需要显式分配,只需要修改/sys/kernel/mm/transparent_hugepage/enabled
为madvise
或always
即可开启THP。
使用大页
为了使用大页,可以使用posix_memalign(3)
分配aligned内存。若为madvise
模式,则需要在代码中使用madvise(ptr, size, MADV_HUGEPAGE)
来在指定区域开启大页。
实例:
void *myMalloc2MbTHP(size_t size) {
void *ptr;
int ret = posix_memalign(&ptr, 1 << 21, size);
if (ret != 0) {
// ERROR HANDLE
}
madvise(ptr, size, MADV_HUGEPAGE);
return ptr;
}
madvise
正如其名,仅提供“建议”,具体是否分配大页还要根据实际情况。如果THP被设置为always
,那么是否madvise(MADV_HUGEPAGE)
就不重要了。
hugetlb和THP的优劣#
THP目前仅支持2MB的大页,不支持1GB大页,因此若想使用1GB大页则只能使用hugetlb。(NV的技术人员已经实现了1GB THP,但还没有merge到linux kernel主流版本中)
THP支持swap,并在需要时先将大页拆分成小页以便swap。此外,THP会尽可能分配大页,并在无法分配大页时falllback到小页分配,整个过程完全透明,用户友好。hugetlb不支持swap。
hugetlb能够保证保留的大页仅用于hugepage使用,这种固定分配方式在不同场景下具有不同的优劣势,需要结合具体使用情况分析。
THP需要守护进程进行大页管理,但其开销很小,对性能影响微乎其微。hugetlb不需要守护进程。