JIT: 현대 CPU에서 인터프리터보다 빨라지고 싶은가요?

JIT: So you want to be faster than an interpreter on modern CPUs

작성자
HackerNews
발행일
2025년 10월 13일

핵심 요약

  • 1 현대 CPU의 OoO 실행 및 분기 예측은 JIT 컴파일러가 최적화된 인터프리터보다 성능 우위를 점하기 어렵게 만듭니다.
  • 2 PostgreSQL 인터프리터는 불필요한 NULL 검사 제거 및 `int4eq` 함수 인라인을 통해 최대 10% 이상의 성능 향상을 달성할 수 있습니다.
  • 3 JIT 컴파일러는 인터프리터가 이미 달성한 최적화와 경쟁해야 하며, 인터프리터의 근본적인 병목 현상 해결이 중요함을 시사합니다.

도입

PostgreSQL용 JIT 컴파일러 개발자는 현대 CPU에서 최적화된 인터프리터를 능가하는 것이 얼마나 어려운지 설명합니다. 글은 CPU의 OoO(Out-of-Order) 실행, 슈퍼스칼라 아키텍처, 분기 예측과 같은 고급 개념을 소개하며, 이러한 요소들이 인터프리터 성능에 미치는 영향을 분석합니다. 저자는 인터프리터 자체의 성능 개선 가능성을 포함하여, 성능 향상을 위한 전략을 모색하고 있습니다.

현대 CPU의 마법: OoO 실행 및 슈퍼스칼라 아키텍처

  • Zen 2+와 Zen 3 CPU의 성능 차이를 예시로 들며, CPU 주파수 증가율보다 훨씬 높은 단일 스레드 성능 향상(2% vs 25%)의 원인을 설명합니다.

  • 1990년대 펜티엄급 CPU부터 x86은 RISC CPU를 따라 슈퍼스칼라 시대로 진입했습니다. 이는 한 사이클에 여러 명령어를 동시에 실행할 수 있게 합니다.

  • f(a, b, c, d) 예시 코드를 통해 독립적인 연산이 동시에 처리될 수 있음을 보여줍니다.

  • OoO(Out-of-Order) 실행은 명령어 의존성을 분석하여 CPU가 유휴 시간을 줄이고 더 빠르게 작업을 완료하도록 돕는 핵심 기술입니다.

  • 분기 예측(branch prediction)은 if/else와 같은 조건문에서 CPU가 미리 결과를 예측하여 실행하고, 예측이 틀리면 되돌리는 방식으로 성능을 극대화합니다. 이는 멜트다운(Meltdown) 같은 보안 문제의 원인이 되기도 했지만, 성능 이점 때문에 비활성화할 수 없습니다.

인터프리터에 미치는 영향

  • 대부분의 인터프리터는 중간 표현(opcode)을 사용하며, 일반적인 switch 문 기반의 메인 루프는 분기 예측 실패로 인해 성능 저하를 겪습니다.

  • 파이썬(Python)과 PostgreSQL 같은 프로젝트에서 사용되는 “computed gotos” 기술은 switch 문을 제거하여 인터프리터 속도를 15-20% 향상시킬 수 있습니다. 이는 연속적인 명령어 실행에서 분기 예측을 더 쉽게 만들어 CPU 효율을 높입니다.

PostgreSQL 인터프리터 최적화: SELECT a FROM table WHERE a = 42 예시

  • 간단한 int4eq 비교 함수를 예로 들어 PostgreSQL의 EEOP_SCAN_FETCHSOME, EEOP_SCAN_VAR, EEOP_FUNCEXPR_STRICT_2, EEOP_QUAL, EEOP_DONE_RETURN 오프코드를 분석합니다.

  • NULL 검사 최적화: FUNCEXPR_STRICT_2 오프코드에서 상수 인수에 대한 불필요한 NULL 검사를 제거함으로써 약 9.5%의 성능 향상(124ms -> 115ms)을 확인했습니다. CPU는 패턴을 학습하지만, 그래도 비용이 발생합니다.

  • 함수 인라인 최적화: int4eq 함수 호출을 오프코드 내부에 직접 인라인하여 FUNCEXPR_STRICT_INT4EQ와 같은 전용 오프코드를 생성하면, 명령어 수와 메모리 주소 점프를 줄여 약 10.3%의 성능 향상(127ms -> 114ms)을 달성할 수 있습니다.

  • 이러한 최적화는 JIT 컴파일러뿐만 아니라 인터프리터에도 동일하게 적용될 수 있으며, JIT 컴파일러가 인터프리터를 능가하기 어렵게 만듭니다.

JIT 컴파일러의 도전

  • 초기에는 NULL 검사 제거를 JIT에서만 구현할 수 있다고 생각했지만, 인터프리터에서도 쉽게 구현 가능함을 깨달았습니다.

  • int4eq와 같은 일반적인 연산을 위한 특수 오프코드 추가 역시 인터프리터에서 가능하여 JIT의 성능 이점을 최소화합니다.

  • 현대 CPU의 분기 예측 및 기타 하드웨어 최적화는 인터프리터의 성능 병목을 크게 줄여, JIT 컴파일러가 압도적인 우위를 점하기 어렵게 만듭니다.

결론

현대 CPU의 OoO 실행 및 분기 예측과 같은 정교한 최적화는 JIT 컴파일러가 인터프리터보다 월등히 빠르다는 인식을 재고하게 만듭니다. 인터프리터 수준에서 NULL 검사 제거, 함수 인라인 등의 최적화가 이미 상당한 성능 향상을 가져왔으며, 이는 JIT 컴파일러가 극복해야 할 도전 과제임을 명확히 합니다. 저자는 인터프리터의 핵심 병목 현상을 해결함으로써 JIT 컴파일러가 여전히 중요한 성능 우위를 확보할 수 있다고 믿으며, 다음 글에서 이를 다룰 것을 예고합니다.

댓글 0

로그인이 필요합니다

댓글을 작성하거나 대화에 참여하려면 로그인이 필요합니다.

로그인 하러 가기

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!