POSIX 또는 Linux에서 대형 페이지 지원 검색

POSIX 또는 Linux에서 대형 페이지 지원 검색

저는 실행 중인 시스템이 거대한 페이지를 지원하는지, 지원한다면 사용 가능한 크기는 얼마인지 런타임에 감지해야 하는 프로그램을 개발 중입니다. 이상적으로는 모든 POSIX 플랫폼에서 작동하고 싶지만 Linux 전용 솔루션이 시작이 될 것입니다.

POSIX 지원sysconf(_SC_PAGESIZE)플랫폼에서 기본 페이지 크기를 가져오지만 큰 페이지 크기를 요구하는 기능은 지원되지 않는 것 같습니다. 시도해봐도 확인할 수 있어요mmap MAP_HUGE_2MB또는 MAP_HUGE_1GB매개변수를 사용하지만 속도가 느리고 1GB의 거대한 페이지의 경우 매우 낭비적입니다(사용 가능한 메모리 부족으로 인해 쉽게 실패함).

답변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 블록, 245 일반 4K 페이지

x23% ./a.out 10000000
addr 0x801000000 len 10000000:
하이퍼맵된 4K 블록 2048개, 일반 4K 페이지 394개

x23% ./a.out 100000000000
addr 0x801000000 len 1215752192:
296448 하이퍼매핑된 4K 블록, 367 일반 4K 페이지

보시다시피 첫 번째 숫자는 "SuperMapped Pages"를 의미합니다. 즉, OS 및 설정에 따라 2Mb, 1Gb 또는 기타 크기의 블록으로 할당된 메모리를 사용하고 백그라운드에서 자동으로 처리된다는 의미입니다.

중요한:이는 memset()중요합니다. 할당된 메모리의 모든 페이지를 커밋합니다. 이 호출이 없으면 할당된 페이지는 1 또는 2가 될 수 있습니다.

답변2

리눅스

내용을 구문 분석 /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()이것솔라리스 9부터:

#include <sys/mman.h>

int size_count = getpagesizes( NULL, 0 );

size_t page_sizes[ size_count ];

getpagesizes( page_sizes, size_count );

관련 정보