我正在开发一个程序,需要在运行时检测其运行的系统是否支持大页面,如果支持,可用的大小是多少。理想情况下,我希望它适用于任何 POSIX 平台,但特定于 Linux 的解决方案将是一个开始。
POSIX 支持sysconf(_SC_PAGESIZE)
获取平台上的默认页面大小,但似乎并不支持要求任何大页面大小。我也可以通过尝试检查mmap
MAP_HUGE_2MB
或MAP_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 );