저는 실행 중인 시스템이 거대한 페이지를 지원하는지, 지원한다면 사용 가능한 크기는 얼마인지 런타임에 감지해야 하는 프로그램을 개발 중입니다. 이상적으로는 모든 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 );