在Linux上如何为C++应用程序分配“大”页面

24
我在Linux上有一个C++应用程序,需要极致的低延迟。我的内存使用量约为2GB,所以使用4KB页面和64个TLB条目,我将会遇到TLB缺失。
我在英特尔开发者手册中读到,2MB(或4MB?)的“巨大”页面只能将TLB条目数量减半,因此内存范围的增加抵消了TLB条目的减少,这样性能会更好。
如何在C++应用程序中分配使用“巨大”页面的内存?有什么需要注意的权衡取舍吗?
我的Linux是Red Hat发行版。

据我所知,您不能混合使用分配类型。您必须配置您的操作系统以使用其中之一。我没有完全阅读它,但是http://linuxgazette.net/155/krishnakumar.html似乎可以满足您的需求。 - RedX
3
@RedX:不,普通系统上可以使用一些2M巨大页面。 grep Huge /proc/meminfo 可以显示当前使用的巨大页面数。在我的桌面电脑(Ubuntu 15.04)上,由于内核注意到一堆连续的4k页面都在使用中,约有400MB的常规malloc分配目前由HugePages支持。请注意,大多数台式机CPU甚至不支持1G HugePages,即使支持,将固定这么多内存也是一个更为小众的用例。参考链接:http://developerblog.redhat.com/2014/03/10/examining-huge-pages-or-transparent-huge-pages-performance/ 。 - Peter Cordes
2
@OP: “减少TLB条目的数量”。您在这里搞砸了。TLB对于4k页面有有限数量的条目,而对于HugePages则有另外一个更小的有限数量的条目。因此,对于一些数据使用HugePages,对于所有通常的常规内容使用常规页面,实际上会增加可用的总TLB条目数量,并显著增加所有TLB条目共同可以覆盖的地址空间的大小。 - Peter Cordes
3个回答

17

您还可以尝试使用透明巨页支持,它在过去几年的任何内核中都可用(至少在3.x和4.x范围以及各种2.6.x内核中)。

主要好处是您不需要设置任何特殊的“hugetlbfs”,它“只需运行”。缺点是不能保证:如果满足某些条件并且有一些可用,内核可能用巨大的页面满足您的分配。与在启动时保留一定数量的巨型页面的hugetlbfs不同,这些页面仅通过特定调用可用,透明巨型页面从一般内存池中划分出巨大的页面。这需要连续的2MB物理内存块,由于物理内存碎片化,随着系统保持时间变长,这些块可能变得罕见。

此外,有各种内核可调整项会影响您是否获得巨型页面,其中最重要的是/sys/kernel/mm/transparent_hugepage/enabled

最好的方法是使用posix_memalign在2MB边界上分配块,然后在第一次触摸之前对分配区域执行madvise(MADV_HUGEPAGE)。它也适用于类似aligned_alloc的变体。根据我的经验,在将/sys/kernel/mm/transparent_hugepage/enabled设置为always的系统上,这通常会导致产生巨型页面。但是,我大多数情况下在具有相当空闲内存和不太长的正常运行时间的系统上使用。

如果您正在使用2GB内存,则可能从巨型页面中获得显着的好处。如果您通过malloc分配所有小块,则透明巨页面不会启用的风险很高,因此您还可以考虑以THP-aware的方式分配使用大部分内存的任何内容(通常是单个对象类型)。

我还编写了一个来确定您是否从任何给定的分配中真正获得了hugepages。这在生产应用程序中可能没有用处,但如果您尝试使用THP路线,它可以成为有用的诊断工具,因为您至少可以确定您是否获得了hugepages。


我认为你的意思是它不是保证的? - user997112
@user997112 - 嗯,已修复。谢谢! - BeeOnRope

10
内核中的“hugetlb”文档可以帮助理解这里的内容。
用户可以通过使用mmap系统调用或标准的SYSV共享内存系统调用(shmget、shmat)在Linux内核中使用大页面支持。
示例:
1) map_hugetlb: 请参考tools/testing/selftests/vm/map_hugetlb.c
2) hugepage-shm: 请参考 tools/testing/selftests/vm/hugepage-shm.c
3) hugepage-mmap: 请参考tools/testing/selftests/vm/hugepage-mmap.c
4) libhugetlbfs (https://github.com/libhugetlbfs/libhugetlbfs)库提供了广泛的用户空间工具,以帮助处理巨大页面的可用性、环境设置和控制。
(这些路径是指Linux源代码树)。
因此,主要有两种方法:
  • 使用带有MAP_HUGETLB标志的mmap
  • 或者,如果存在,则从挂载的hugetlb文件系统映射一个文件

7

我假设你只需要为使用C++编写的特定应用程序创建巨大页面,否则只需更改系统的页面大小。以下方法适用于使用任何语言编写的应用程序。

  1. In order to use huge pages for specific application you need to build your kernel for the support of huge page support. you must build kernel with CONFIG_HUGETLBFS options

  2. Specify page size by specifying

    hugepagesz=<size>
    

    on boot command line

  3. To see how to set boot parameters: http://www.cyberciti.biz/tips/10-boot-time-parameters-you-should-know-about-the-linux-kernel.html

  4. To set the no of huge pages use

    # echo 20 > /proc/sys/vm/nr_hugepages
    
  5. To check the huge pages (available, total, …)

    # cat /proc/meminfo
    
  6. When all above goes fine, now you have to work with “how to use these pages for particular application”: mount file system of type hugetlbfs as

    # mount -t hugetlbfs -o uid=<value>,gid=<value>,mode=<value>,pagesize=<value>,size=<value>,min_size=<value>,nr_inodes=<value> none /mnt/huge
    

    place your application on this mount /mnt/huge boom now your application will use page size set by you!

更多细节请查看https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt

大页的优缺点:

优点:由于减少了TLB损失率,减少了页面故障,并且减少了页面表的大小以及较少的转换,因此效率高。

缺点:更多的内部碎片:内存损失,交换中的延迟增加(HUGETLBFS页面不交换它们的映射是永久的)。更多细节请查看https://lwn.net/Articles/359158/

编辑 还有API可用于分配大页,请检查可能会有帮助

https://github.com/libhugetlbfs/libhugetlbfs/blob/master/HOWTO

https://lwn.net/Articles/375096/


6
将您的应用程序放置在此挂载点 /mnt/huge 上,现在您的应用程序将使用您设置的页面大小!但是不建议将可执行文件复制到挂载点,实际上这很困难甚至不可能完成。相反,想要使用大页的程序应该映射挂载点上的文件。 - davmac
是的,当我重新查看你的问题时,我意识到了其中的复杂性。我更新了我的答案,添加了API,也许可以解决你的问题,但我不知道它的用法。 - incompetent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接