POSIXまたはLinuxで大きなページサポートを検索する

POSIXまたはLinuxで大きなページサポートを検索する

私は実行中のシステムが巨大なページをサポートしているのか、それをサポートしているなら、利用可能なサイズはどのくらいであるかを実行時に検出する必要があるプログラムを開発しています。理想的には、すべてのPOSIXプラットフォームで動作したいのですが、Linux専用のソリューションが始まりになります。

POSIX サポートsysconf(_SC_PAGESIZE)プラットフォームはデフォルトのページサイズを取得しますが、大きなページサイズを必要とする機能はサポートされていないようです。試してみても確認できます。mmap MAP_HUGE_2MBまたはMAP_HUGE_1GB、パラメータを使用しますが、速度が遅く、1 GBの巨大ページの場合は非常に無駄です(使用可能なメモリ不足のために簡単に失敗します)。

答え1

libhugetlbfsプログラマーとしてLinuxを使用すると、後ろからすべてを処理するという利点を享受できます。 (注:不要な場合があります。わかりません。まだテストが必要です。)

メモリを管理するすべての機能を独自のバージョンに置き換え、可能であれば自動的に大容量ページに切り替えます。これには、何malloc()よりもスタック割り当てが含まれますmmap()fork()

Ubuntuでは、次のようにライブラリをインストールできます。

sudo apt-get install libhugetlbfs-dev

その後、次のようなものを使用できます。get_huge_pages()巨大なページに大きなバッファを割り当てたい場合。malloc()ライブラリのインストール後にマニュアルページが必要になるため、詳細は次のとおりです。

man get_huge_page

オペレーティングシステム機能もあり、mincore()、メモリ領域で使用される大小のページ(4K)数を取得できます。以下はBSDコードでの使用例です(この関数のソースはBSDです)。これは確かにUnicesで探しているものです(IRIX、HP-UX、AIXなどのすべてのUnixオペレーティングシステムでは機能しない可能性がありますが…確認する必要があります)。この機能は常に利用可能です。それを使用するためのライブラリは必要ありません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 ブロック

x23
%

x23
%

ご覧のとおり、最初の数字は「SuperMapped Pages」を意味します。つまり、OSや設定によっては、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 );

FreeBSD

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 );

関連情報