发现 POSIX 或 Linux 上的大页面支持

发现 POSIX 或 Linux 上的大页面支持

我正在开发一个程序,需要在运行时检测其运行的系统是否支持大页面,如果支持,可用的大小是多少。理想情况下,我希望它适用于任何 POSIX 平台,但特定于 Linux 的解决方案将是一个开始。

POSIX 支持sysconf(_SC_PAGESIZE)获取平台上的默认页面大小,但似乎并不支持要求任何大页面大小。我也可以通过尝试检查mmap MAP_HUGE_2MBMAP_HUGE_1GB参数,但这会很慢,并且在 1GB 大页面的情况下,非常浪费(并且由于缺乏可用内存,它很容易失败)。

答案1

对于 Linux,作为一名程序员,您可能希望利用它libhugetlbfs在幕后为您处理一切。 (注意:甚至可能不需要,我不确定,我仍然需要测试)。

它用自己的版本替换了所有管理内存的函数,如果可能的话,它会自动切换到大页面。这将包括分配堆栈malloc()mmap()其他内容。fork()

使用 Ubuntu,您可以通过以下方式安装该库:

sudo apt-get install libhugetlbfs-dev

然后您可以使用诸如get_huge_pages()如果您确实想在大页面中分配大缓冲区。这相当于malloc().安装库后,您应该拥有手册页,因此有关详细信息,您可以执行以下操作:

man get_huge_page

还有一个操作系统功能,mincore(),它允许您获取内存区域使用的大页和小页 (4K) 的数量。下面有一个在 BSD 代码中使用的示例(该函数来自哪里,它是 BSD 的东西)。这肯定是您在 Unices 下寻找的东西(尽管它可能不适用于所有 Unix 操作系统,例如 IRIX、HP-UX、AIX...您必须检查一下)。请注意,此功能始终可用。您不需要该libhugetlbfs库即可使用它。请注意,在 Linux 下,除了位 0 之外,它们似乎没有设置任何其他内容,这意味着您只知道页面是否驻留,而不是像 BSD 中那样知道页面的大小。

我几乎只在 Linux 下工作。但对于 MS-Windows,这称为“大页面”。他们在这里有文档:https://docs.microsoft.com/en-us/windows/win32/memory/large-page-support

最后,各种 BSD 实现将这些称为“超级页面”(因此 macos 使用该接口)。我发现这一页代码示例显示了有多少超级页面被用于大型malloc().

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

int 
main(int argc, char **argv)
{
        size_t size, flags, i, super = 0, ordinary = 0;
        void *addr;
        char *vec;

        if (argc != 2)
                return (0);

        size = atoi(argv[1]);
        addr = malloc(size);
        vec = malloc(size / 4096);

        memset(addr, 0, size);

        flags = mincore(addr, size, vec);

        printf("addr %p len %d:\n", addr, size);
        for (i = 0; i <= size / 4096; i++)
                if (vec[i] & MINCORE_SUPER)
                        super++;
                else
                        ordinary++;
        printf("%d 4K blocks super-mapped, %d ordinary 4K pages\n",
            super, ordinary);

        return (0);
}

以及该 FreeBSD 代码的一些输出:

x23% ./a.out 1000000
addr 0x801006000 len 1000000:
0个4K块超映射,245个普通4K页

x23% ./a.out 10000000
addr 0x801000000 len 10000000:
2048个4K块超映射,394个普通4K页

x23% ./a.out 100000000000
addr 0x801000000 len 1215752192:
296448个4K块超映射,367个普通4K页

正如我们所看到的,第一个数字代表“超级映射页面”,这意味着它使用以 2Mb 或 1Gb 或其他大小的块分配的内存,具体取决于您的操作系统和设置,并且它是在后台自动处理的。

重要的:memset()很重要,它提交了已分配内存的所有页面。如果没有该调用,分配的页面可能是 1 或 2...

答案2

Linux

解析内容/sys/kernel/mm/hugepages(这是什么libhugetlbfs什么

[~]# ls -l /sys/kernel/mm/hugepages/
total 0
drwxr-xr-x 2 root root 0 Dec 30 16:38 hugepages-1048576kB
drwxr-xr-x 2 root root 0 Dec 30 16:38 hugepages-2048kB
[~]# 

在 C 中(为了清楚起见,省略了标头和错误检查):

// 16 should be plenty for this example (should really do this dynamically)
int size_count = 1;

// use unsigned long long to match strtoull()
unsigned long long page_sizes[ 16 ];

// get the base page size
page_sizes[ 0 ] = sysconf( _SC_PAGESIZE );

// now get the huge page size(s)
DIR *dirp = opendir( "/sys/kernel/mm/hugepages" );
for ( ;; )
{
    struct dirent *dirent = readdir( dirp );
    if ( NULL == dirent ) break;

    if ( '.' == dirent->d_name[ 0 ] ) continue;

    char *p = strchr( dirent->d_name, '-' );
    if ( NULL == p ) continue;

    page_sizes[ size_count++ ] = 1024ULL * strtoull( p + 1, NULL, 0 ); 
}

closedir( dirp );

如果您已经libhugetlbfs-dev安装:

#include <hugetlbfs.h>

int size_count = getpagesizes( NULL, 0 );

long page_sizes[ size_count ];

getpagesizes( page_sizes, size_count );

与 -lhugetlbfs 链接

索拉里斯

在C中,使用getpagesizes()

#include <sys/mman.h>

int size_count = getpagesizes( NULL, 0 );

size_t page_sizes[ size_count ];

getpagesizes( page_sizes, size_count );

自由BSD

FreeBSD 已复制getpagesizes()从 Solaris 9 开始:

#include <sys/mman.h>

int size_count = getpagesizes( NULL, 0 );

size_t page_sizes[ size_count ];

getpagesizes( page_sizes, size_count );

相关内容