--- id: efce9a6e-5f5d-45ec-86e5-056d8cb1b8d2 kind: CONCEPT slug: huge-pages-in-a-vm title: Huge Page 를 VM 에서 볼 때 갈라지는 세 자리 topic: memory-virtualization topicName: 메모리 가상화 project: virtualization status: 초안 basisVersion: Linux THP(/sys/kernel/mm/transparent_hugepage/enabled) · HugeTLB pool · x86-64 의 4 KiB / 2 MiB / 1 GiB page studio: "https://hyeonworks.com/studio/documents/efce9a6e-5f5d-45ec-86e5-056d8cb1b8d2/edit" sourceRevision: no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다 source: - final/document.md#50-huge-page가-필요한-이유 - final/document.md#51-huge-page와-tlb-coverage - final/document.md#52-vm에서-huge-page를-볼-때-주의할-점 - final/document.md#53-thp-transparent-huge-pages - final/document.md#54-thp의-trade-off - final/document.md#55-hugetlb - final/document.md#56-thp와-hugetlb-비교 - final/document.md#82-핵심-claim-registry --- # Huge Page 를 VM 에서 볼 때 갈라지는 세 자리 페이지 크기를 키우면 같은 메모리 범위를 더 적은 매핑으로 표현할 수 있고, TLB(Translation Lookaside Buffer, 주소 변환 캐시) 엔트리 하나가 덮는 범위도 넓어진다. 그런데 가상 머신에는 주소 변환 단계가 둘이라 「Huge Page 를 쓴다」는 말만으로는 어디를 말하는지 정해지지 않는다. 게스트 페이지 테이블 단계인지, QEMU 가 마련한 호스트 쪽 메모리인지, EPT(Extended Page Tables) 매핑인지를 나누어 물어야 그 말이 뜻을 갖는다. Linux 가 큰 페이지를 마련하는 방법도 THP(Transparent Huge Pages)와 HugeTLB 두 가지인데, 둘은 관리 주체도 사전 예약 여부도 다르다. ## 관계 - **Guest 메모리 주소가 물리 RAM 에 닿기까지 — GVA · GPA · HPA** 페이지 크기 선택이 걸리는 두 변환 단계를 그 글이 세운다. - **이 호스트의 THP 정책과 huge page 상태는 무엇인가** 이 서버의 THP 정책과 huge page 관련 값을 읽는 질문이다. 이 글은 그 값이 무엇을 뜻하는지까지만 적었다. - **가상 머신 RAM 이 HugeTLB 로 명시적으로 backing 되어 있는가** 세 곳 가운데 호스트 쪽을 이 서버에서 확인하는 질문이다. - **메모리 실험 결과에는 Host · VM · Workload 조건을 함께 남긴다** THP 정책과 huge page 설정은 그 기준이 요구하는 기록 항목에 들어간다. ## 본문 ## 페이지가 커지면 매핑 수가 준다 같은 메모리 범위라도 페이지 크기에 따라 필요한 매핑 수가 달라진다. 원문은 8 GiB 를 예로 들어 셋을 나란히 계산했다. | 페이지 크기 | 8 GiB 를 표현하는 데 필요한 페이지 수 | |---|---| | 4 KiB | 2,097,152 pages | | 2 MiB | 4,096 pages | | 1 GiB | 8 pages | 큰 페이지는 더 적은 매핑으로 넓은 메모리 범위를 표현할 수 있다. 위 8 GiB 는 계산을 보이려고 원문이 든 예시 값이고 이 서버 가상 머신의 설정이 아니다. ## TLB 엔트리 하나가 덮는 범위 TLB 엔트리 하나가 가리키는 페이지가 커지면 캐시된 변환 하나로 더 넓은 주소 범위를 덮을 수 있다. ```text label="mapping 수가 같을 때 덮이는 범위 (원문의 단순 예)" 4 KiB page × 512 mappings = 2 MiB coverage 2 MiB page × 512 mappings = 1 GiB coverage ``` 실제 CPU 는 페이지 크기마다 TLB 구조와 엔트리 수가 다르기 때문에, 이 숫자를 특정 CPU 의 실제 TLB 용량으로 해석하면 안 된다. 여기서 남는 것은 방향 하나다. 페이지 크기가 커지면 변환 하나가 덮는 범위가 넓어지고 TLB 압박이 줄어들 가능성이 생긴다. 페이지 테이블 엔트리 수와 페이지 테이블 탐색 부담도 함께 줄어들 가능성이 있다. ## 가상 머신에서는 세 곳을 따로 물어야 한다 가상 머신에는 GVA(Guest Virtual Address)를 GPA(Guest Physical Address)로 바꾸는 단계와, 그 GPA 를 HPA(Host Physical Address)로 바꾸는 단계가 있다. ```text label="page 크기 선택이 걸릴 수 있는 두 변환 단계" GVA │ Guest Page Table ▼ GPA │ EPT ▼ HPA ``` 그래서 "Huge Page를 사용한다"는 말만으로는 부족하다. 세 가지를 갈라 물어야 한다. - 게스트 페이지 테이블 단계에서 큰 페이지를 쓰는가? - 호스트가 그 메모리를 Huge Page 로 받치고 있는가? - EPT 매핑에서 큰 매핑을 활용하는가? 게스트와 호스트의 페이지 크기 선택을 같은 설정 하나로 묶어 다루면 안 된다. 게스트 안에서 THP 가 켜져 있어도 그것은 첫 질문에 대한 답이고, 그 가상 머신의 RAM 을 호스트가 무엇으로 받치는지는 두 번째 질문이 따로 받는다. ## THP — 커널이 조건이 맞을 때 알아서 쓰는 방식 THP 는 Linux 가 가능한 메모리 영역에 대해 Huge Page 를 투명하게 활용하려는 기능이다. 애플리케이션이 평소처럼 `malloc()` 이나 `mmap()` 을 부르면 커널이 조건이 맞는 영역에 Huge Page 활용을 시도한다. 애플리케이션이 큰 페이지를 달라고 따로 요청하지 않는다는 뜻에서 투명하다. 지금 어떤 정책이 걸려 있는지는 `/sys/kernel/mm/transparent_hugepage/enabled` 에서 읽는다. ```bash label="THP 정책 확인" cat /sys/kernel/mm/transparent_hugepage/enabled ``` ```text label="정책 값의 예 — 대괄호가 현재 선택된 값이다" always [madvise] never ``` 이 값은 커널과 배포판, 호스트 설정에 따라 다르므로 실제 시스템에서 확인한다. 그래서 원문은 메모리 실험마다 반드시 같이 남길 조건 목록에 THP policy 를 Host 항목으로, Memory backing 설정을 VM 항목으로 넣어 두었다. 조건을 남기지 않으면 "Memory pressure에서 느려졌다"는 결과를 다른 환경에 재사용하기 어렵다는 것이 그 목록에 붙은 이유다. ## THP 가 치르는 비용 Huge Page 에는 이어진 큰 물리 메모리 영역이 필요하다. 2 MiB 하나가 4 KiB 페이지 512 개에 해당해서, 그만큼 이어진 영역을 확보하지 못하면 커널이 compaction 같은 작업을 수행할 수 있다. ```text label="fragmentation 이 심할 때 끼어드는 작업" Huge Page 필요 ↓ 큰 contiguous memory 필요 ↓ Fragmentation ↓ Compaction 가능 ↓ Latency 영향 가능 ``` 그래서 THP 는 항상 성능을 높인다고 단정할 수 없다. 특히 지연에 민감한 워크로드에서는 측정이 필요하다고 원문이 직접 적었고, 이 서버에서 그 측정을 하지 않았다. ## HugeTLB — 미리 확보해 둔 풀 HugeTLB 는 Huge Page 풀을 명시적으로 두고 쓸 수 있는 Linux 메커니즘이다. 커널이 알아서 활용하는 THP 와 달리, 관리자가 풀을 준비하고 애플리케이션이나 가상 머신이 그 풀을 명시적으로 쓴다. ```text label="Host physical RAM 안에 잡아 둔 pool" Physical RAM ┌──────────────────────────┐ │ Normal Memory │ ├──────────────────────────┤ │ HugeTLB Pool │ │ 2 MiB │ │ 2 MiB │ │ 2 MiB │ │ ... │ └──────────────────────────┘ ``` 미리 확보해 두면 예측 가능성을 높일 수 있지만, 풀로 떼어 둔 만큼은 일반 할당이 쓸 수 없기 때문에 일반적인 메모리 할당의 유연성은 그만큼 줄어든다. ## 둘을 가르는 여섯 항목 | 무엇을 견주나 | THP | HugeTLB | |---|---|---| | 관리 | 커널이 투명하게 활용 | 명시적인 풀 | | 애플리케이션 개입 | 상대적으로 적음 | 명시적 구성 가능 | | 유연성 | 상대적으로 높음 | 상대적으로 낮음 | | 사전 예약 | 핵심 방식 아님 | 가능 | | compaction 영향 | 발생 가능 | 미리 확보해 일부 상황 회피 가능 | | 가상 머신 RAM backing | 사용 가능 | 명시적으로 사용 가능 | 호스트에서 두 값을 함께 읽으면 어느 쪽이 쓰이고 있는지 갈린다. ```bash label="Host 의 huge page 상태와 THP 정책" grep -i huge /proc/meminfo cat /sys/kernel/mm/transparent_hugepage/enabled ``` `AnonHugePages` 와 `HugePages_Total` 은 같은 뜻이 아니다. 앞의 값은 익명 메모리에서 THP 로 쓰이고 있는 양이고, 뒤의 값은 HugeTLB 풀로 확보해 둔 페이지 수다. 한쪽이 0 이어도 다른 쪽이 커질 수 있어서, 두 값을 한 이름으로 묶어 읽으면 어떤 방식이 돌고 있는지 알 수 없다. ## 이 글이 확정하지 않는 것 이 호스트에서 잰 값은 하나도 없다. THP 정책도 `HugePages_Total` 도 읽지 않았고 가상 머신의 메모리 backing 설정도 확인하지 않았다. 원문 제2부는 개념 서술이고 실제 서버에 딸린 값은 OQ(Open Question) 번호가 붙은 확인 목록 열넷으로 미뤄져 있다. 호스트 쪽 값은 OQ-4 가 받는다. THP 정책과 함께 `AnonHugePages`, `HugePages_Total`, `HugePages_Free`, `Hugepagesize` 를 읽어 이 서버가 어느 방식을 쓰고 있는지 확정하는 확인이다. 가상 머신 쪽 backing 은 OQ-5 가 받는다. libvirt 의 memory backing 설정을 읽고 호스트의 `/proc/meminfo`, QEMU 의 `smaps` 계열 값과 교차 검증한다. ```bash label="OQ-5 가 읽을 가상 머신 정의" virsh dumpxml ``` 두 확인이 끝나기 전에는 이 글의 세 질문 가운데 어느 것도 이 서버에 대해 답이 없다. 그리고 두 확인이 끝나도 셋째 질문은 남는다. EPT 매핑에서 큰 매핑을 쓰는가를 이 호스트에서 재라고 적은 항목은 그 열넷에 없다. 원문이 커널·QEMU·libvirt 버전을 적지 않아 이 글도 특정 버전에 고정하지 않았고, THP 정책의 기본값이 배포판마다 다르다는 점도 원문이 확인하라고만 적었다.