[Linux] Transparent Huge Pages

bluewhale·2025년 9월 16일

Linux

목록 보기
3/3

요약

  • 대형 페이지(Huge Page) 기능을 활용하여 TLB miss로 인한 오버헤드를 최소화할 수 있습니다.
  • 워킹셋의 데이터가 크고 (수십 MB~), 메모리 접근이 매우 빈번한 워크로드에 유용한 최적화입니다.
    • 주로 데이터베이스 시스템과 관련된 레퍼런스(Oracle, Postgres, AWS RDS)가 많습니다.
    • 대형 JVM 어플리케이션
    • 하이퍼바이저 (KVM/QEMU)
    • 대규모 분석/검색 시스템 (ex, ClickHouse)
  • CPU 및 I/O 바운드가 지배적인 워크로드에서는 별다른 효용이 없을 수 있습니다.

배경

  • 모든 프로세스는 가상 메모리 주소 공간을 할당 받습니다.
  • 프로세스에서 가상 메모리 주소에 접근하면 CPU는 이를 실제 물리 메모리 주소로 치환하여 처리합니다.
  • OS는 가상 메모리 주소를 물리 메모리 주소로 매핑하기 위한 Page Table을 관리합니다.

  • 프로세스가 메모리에 접근할 때 마다, 가상 메모리 주소 → 물리 메모리 주소 변환이 매번 발생합니다.
  • CPU는 이를 최적화 하기 위해 최근 변환된 메모리 주소를 캐싱합니다 → Translation Lookaside Buffer (TLB)

  • 문제는 TLB의 크기가 일반적으로 매우 작습니다. (~ 4KB)
  • 따라서, 워킹 셋의 크기가 큰 경우에는 TLB 미스가 빈번하게 발생합니다.
  • TLB의 크기는 제한적이므로, 대신 페이지 의 크기를 크게 만들어서 TLB hit를 높이는 방법이 고안되었습니다.

Huge Pages

  • 리눅스에서는 페이지 크기를 늘릴 수 있는 두 가지 옵션을 제공합니다.
    • hugetlbfs
      • 리눅스에서 대형 페이지(Huge Page)를 활용하기 위해 제공되는 특별한 파일시스템입니다.
        • 커널이 제공하는 가상 파일시스템으로, /dev/hugepages 와 같은 경로를 마운트할 수 있습니다.
        • 프로세스가 이 파일시스템에 파일을 만들고 mmap() 을 하면, 그 매핑은 대형 페이지 단위로 할당됩니다.
        • 즉, 일반적인 malloc 이 아니라 hugetlbfs 로 마운트한 경로를 통해 대형 페이지 메모리를 사용합니다.
      • 특징
        • 시스템 메모리 중, hugetlbfs에서 사용할 대형 페이지 개수를 미리 설정해야 합니다.
          • 예약된 대형 페이지는 다른 용도로 사용되지 않습니다.
          • 어플리케이션에서 이를 사용하지 않으면 그냥 낭비됩니다.
        • 어플리케이션 코드에서 메모리를 사용하는 방식의 전환이 필요합니다.
          • 명시적으로 메모리를 할당하는 C와 같은 프로그램은 코드 수정이 요구됩니다.
          • JVM과 같은 런타임에서는 옵션(-XX:+UseHugeTLBFS)을 사용하면 적용할 수 있습니다.
      • 활용 레퍼런스
        • 초단타 매매(HFT), 데이터베이스(Oracle, Postgres, AWS RDS) 및 캐시 서버 등에서 활용됩니다.
    • Transparent Huge Pages (THP)

검증

  • 아래는 벤치마크 테스트에 활용된 코드 예시입니다.
    • 임의의 크기의 byte[] 를 생성하고 랜덤한 인덱스에 접근합니다.
    • 바이트 배열의 크기가 커질수록 많은 page가 할당되며 TLB miss가 발생할 가능성이 높아집니다.
public class ByteArrayTouch {

    @Param(...)
    int size;

    byte[] mem;

    @Setup
    public void setup() {
        mem = new byte[size];
    }

    @Benchmark
    public byte test() {
        return mem[ThreadLocalRandom.current().nextInt(size)];
    }
}
  • 벤치마크 테스트 결과, 바이트 배열의 크기가 큰 구간에서 최대 15% 수준의 성능 개선이 이뤄졌습니다.
Benchmark               (size)  Mode  Cnt   Score   Error  Units

# Baseline
ByteArrayTouch.test       1000  avgt   15   8.109 ± 0.018  ns/op
ByteArrayTouch.test      10000  avgt   15   8.086 ± 0.045  ns/op
ByteArrayTouch.test    1000000  avgt   15   9.831 ± 0.139  ns/op
ByteArrayTouch.test   10000000  avgt   15  19.734 ± 0.379  ns/op
ByteArrayTouch.test  100000000  avgt   15  32.538 ± 0.662  ns/op

# -XX:+UseTransparentHugePages
ByteArrayTouch.test       1000  avgt   15   8.104 ± 0.012  ns/op
ByteArrayTouch.test      10000  avgt   15   8.060 ± 0.005  ns/op
ByteArrayTouch.test    1000000  avgt   15   9.193 ± 0.086  ns/op // !
ByteArrayTouch.test   10000000  avgt   15  17.282 ± 0.405  ns/op // !!
ByteArrayTouch.test  100000000  avgt   15  28.698 ± 0.120  ns/op // !!!

# -XX:+UseHugeTLBFS
ByteArrayTouch.test       1000  avgt   15   8.104 ± 0.015  ns/op
ByteArrayTouch.test      10000  avgt   15   8.062 ± 0.011  ns/op
ByteArrayTouch.test    1000000  avgt   15   9.303 ± 0.133  ns/op // !
ByteArrayTouch.test   10000000  avgt   15  17.357 ± 0.217  ns/op // !!
ByteArrayTouch.test  100000000  avgt   15  28.697 ± 0.291  ns/op // !!!
  • CPU 카운터를 분석해본 결과
    • 일반 페이지를 사용한 경우 100%에 가까운 TLB miss가 발생하였습니다.
    • 반면, THP를 사용한 경우 TLB 미스가 거의 발생하지 않았습니다.
Benchmark                                (size)  Mode  Cnt    Score    Error  Units

# Baseline
ByteArrayTouch.test                   100000000  avgt   15   33.575 ±  2.161  ns/op
ByteArrayTouch.test:cycles            100000000  avgt    3  123.207 ± 73.725   #/op
ByteArrayTouch.test:dTLB-load-misses  100000000  avgt    3    1.017 ±  0.244   #/op  // !!!
ByteArrayTouch.test:dTLB-loads        100000000  avgt    3   17.388 ±  1.195   #/op

# -XX:+UseTransparentHugePages
ByteArrayTouch.test                   100000000  avgt   15   28.730 ±  0.124  ns/op
ByteArrayTouch.test:cycles            100000000  avgt    3  105.249 ±  6.232   #/op
ByteArrayTouch.test:dTLB-load-misses  100000000  avgt    310⁻³            #/op  // !!!
ByteArrayTouch.test:dTLB-loads        100000000  avgt    3   17.488 ±  1.278   #/op

레퍼런스

profile
안녕하세요

0개의 댓글