Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 774 – JIT 빌드에서 LLVM 요구 사항 제거

Author:
Savannah Ostrowski <savannah at python.org>
Discussions-To:
Discourse thread
Status:
Deferred
Type:
Standards Track
Created:
27-Jan-2025
Python-Version:
3.14
Post-History:
27-Jan-2025
Resolution:
14-Mar-2025

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

Python 3.13부터 CPython은 Linux와 Mac에서는 --enable-experimental-jit 플래그를, Windows에서는 --experimental-jit 플래그를 사용해 실험적인 JIT(just-in-time) 컴파일러를 포함하도록 구성하고 빌드할 수 있습니다. JIT를 활성화한 상태로 CPython을 빌드하려면 사용자의 머신에 LLVM이 설치되어 있어야 합니다(처음에는 LLVM 16이 필요했지만 최근에는 LLVM 19가 필요합니다). LLVM은 우리의 복사 후 패치(copy-and-patch) JIT에 필수적인 스텐실을 생성하는 역할을 합니다(PEP 744 참조). 이 스텐실은 미리 정의된 아키텍처별 템플릿으로, 런타임에 기계어 코드를 생성하는 데 사용됩니다.

이 PEP는 생성된 스텐실을 CPython 저장소에 두어, JIT를 활성화한 빌드에서 LLVM 빌드 타임 의존성을 제거할 것을 제안합니다. 이 방식을 사용하면 지원되는 플랫폼에서는 빌드할 때 저장소에 체크인된 스텐실을 활용할 수 있으므로, 기여자 경험이 단순해지고 2024년 9월 Python 코어 개발자 스프린트에서 제기된 우려도 해소됩니다. 다만 개발자 경험이 개선되는 대신 저장소 크기가 커지므로, 분명히 고려해야 할 트레이드오프가 있습니다.

이 PEP는 JIT 자체의 채택이나 거부를 제안하는 것이 아니라, 앞으로 JIT 빌드에서 LLVM 빌드 타임 의존성을 받아들일 수 있는지를 결정하기 위한 것이라는 점에 유의해야 합니다. 이 PEP가 거부되면 LLVM 빌드 타임 요구 사항을 유지한 채 현 상태대로 진행합니다. 이 의존성은 지금까지 JIT 개발 과정에서 효과적으로 쓰였지만, 설정을 복잡하게 만들고 추가적인 어려움을 초래하며, 이 PEP는 이를 완화하고자 합니다.

동기

2024년 9월에 열린 Python 코어 개발자 스프린트에서 JIT의 다음 단계에 관한 논의가 있었으며, 관련 논의가 GitHub에서도 진행되었습니다. 그 논의에서는 3.14에서 JIT를 기본적으로 비활성화한 상태로 출시하는 것에 대비하여 JIT 빌드의 LLVM 요구 사항을 제거하자는 요구도 분명히 있었습니다. 스프린트에서는 Tier 1 플랫폼의 비디버그 빌드용으로 미리 생성한 스텐실을 제공하면 충분하고, 플랫폼 수가 제한적이므로 이 파일들을 CPython 저장소에 체크인해도 적절하다는 데 합의했습니다(다른 방안도 검토했습니다. Rejected Ideas를 참조하십시오).

현재 JIT를 포함하여 CPython을 빌드하려면 빌드 타임 의존성으로 LLVM이 필요합니다. 이 의존성은 최종 사용자에게 노출되지는 않지만 바람직하지 않습니다. LLVM이 필요하면 개발자와 JIT를 활성화하여 CPython을 빌드하려는 사람들에게 설정 부담이 생깁니다. 운영 체제에 따라서는 OS에 포함된 LLVM 버전이 JIT 빌드에 필요한 버전과 다를 수 있으며, 이 때문에 문제를 진단하고 해결하는 일이 더 복잡해집니다. 현재 JIT에 기여하고 JIT를 유지 관리하는 코어 개발자가 많지 않으므로, JIT 관련 코드 작업의 마찰도 최대한 줄이고자 합니다.

제안하는 방식에서는 지원되는 아키텍처용으로 미리 컴파일한 스텐실을 사전에 생성하여 한 곳에 저장해 두고, 빌드할 때 자동으로 사용할 수 있습니다. 이 방식은 재현 가능한 빌드를 보장하며, JIT가 앞으로 CPython에서 더 안정적이고 지속 가능한 부분이 되도록 합니다.

근거

이 PEP는 LLVM 빌드 타임 의존성을 없애는 가장 좋은 방법으로 JIT 스텐실을 CPython 저장소에 직접 체크인할 것을 제안합니다.

이 방식은 다음과 같습니다.

  • JIT를 포함하여 CPython을 빌드하려는 사람들에게 처음부터 끝까지 가장 좋은 경험을 제공합니다
  • JIT에 기여하려는 사람들의 진입 장벽을 낮춥니다
  • 외부 인프라나 다운로드 방식에 의존하지 않고도 모든 플랫폼에서 빌드가 재현 가능하고 일관되게 유지되도록 보장합니다
  • 네트워크 상태, 또는 호스팅된 파일과 CPython 저장소 상태 사이에 생길 수 있는 불일치 때문에 발생하는 변동을 없앱니다
  • 스텐실이 다른 모든 JIT 관련 코드와 같은 리뷰 과정을 거치도록 합니다

그러나 이 방식은 전체 저장소 크기를 약간 증가시킵니다. 지난 90일간의 커밋으로 인한 저장소 증가량을 비교해 보면, 실제 커밋과 같은 커밋에 스텐실을 추가한 경우의 차이는 스텐실 파일당 0.03 MB입니다. 같은 기간 동안 전체 저장소 크기가 2.55 MB 증가한 것을 고려하면 이는 작은 증가입니다. 스텐실 파일 6개를 기준으로 하면 증가량은 최대 0.18 MB입니다. 현재 6개 플랫폼 전체의 스텐실 파일 총 크기는 7.2 MB입니다. [1]

앞으로 레지스터 할당이 변경되면 이 스텐실들이 더 커질 수 있습니다. 이 경우 각 스텐실 파일에 명령어당 5~6개의 변형이 추가되어 크기가 5~6배 커집니다. 그러나 이 방향으로 가게 되더라도, 스텐실 파일을 추가로 수정하여 이러한 크기 증가를 상쇄할 수 있습니다(예: 주석 제거, 스텐실 최소화).

명세

이 명세는 LLVM에 대한 빌드 시점 의존성을 제거하기 위해 제안하는 변경 사항과, 이 PEP가 채택될 경우의 기여자 경험을 설명합니다.

저장소 변경 사항

이제 CPython 저장소는 미리 컴파일된 JIT 스텐실을 Tools/jit 안의 새 하위 디렉터리인 stencils/에 보관하게 됩니다. 현재 JIT는 6개 플랫폼에서 테스트되고 빌드되므로, 우선은 스텐실 파일 6개를 체크인합니다. 앞으로 추가 플랫폼 지원이 필요하거나 적절하다고 판단되면 스텐실 파일을 더 체크인할 수 있습니다.

cpython/
    Tools/
        jit/
            stencils/
                aarch64-apple-darwin.h
                aarch64-unknown-linux-gnu.h
                i686-pc-windows-msvc.h
                x86_64-apple-darwin.h
                x86_64-pc-windows-msvc.h
                x86_64-pc-linux-gnu.h

워크플로

워크플로 변경 사항은 JIT를 활성화한 CPython 빌드와 JIT 구현 작업이라는 두 부분으로 나눌 수 있습니다.

JIT를 활성화한 CPython 빌드

미리 컴파일된 JIT 스텐실 파일은 Tools/jit/stencils 디렉터리에 저장되며, 각 파일 이름은 앞서 설명한 대로 해당 타깃 트리플에 대응합니다. 빌드 시점에, 체크인된 스텐실을 사용할지 아니면 사용자의 플랫폼에 맞는 새 스텐실을 생성할지 결정합니다. 구체적으로, LLVM이 설치된 기여자는 Tools/jit/stencils에 있는 build.py 스크립트로 자신의 플랫폼에 맞는 스텐실을 다시 생성할 수 있습니다. LLVM이 없는 기여자는 저장소에 있는 미리 컴파일된 스텐실 파일을 그대로 사용할 수 있습니다.

JIT 구현 작업(또는 JIT 파일 수정)

지속적 통합(CI)에서는 JIT 관련 파일이 변경되면 스텐실 파일이 자동으로 검증되고 갱신됩니다. 이 파일들을 수정하는 풀 리퀘스트가 열리면, 빌드를 수행하고 테스트하는 jit.yml 워크플로가 평소와 같이 실행됩니다.

다만 여기에 더해, 저장소에 있는 현재 스텐실과 CI에서 생성된 스텐실을 비교(diff)하는 새로운 단계를 도입합니다. 어떤 플랫폼의 스텐실 파일에 차이가 있으면 갱신된 스텐실에 대한 패치 파일이 생성되고 해당 단계는 실패합니다. 각 패치는 GitHub Actions에 업로드됩니다. 모든 플랫폼에서 CI 실행이 끝나면, 편의를 위해 패치들이 하나의 패치 파일로 합쳐집니다. 이 합쳐진 패치를 내려받아 로컬에 적용한 다음, 갱신된 스텐실을 자신의 브랜치에 커밋하면 됩니다. 그러면 이후의 CI 실행은 통과합니다.

참조 구현

참조 구현의 핵심 부분은 다음과 같습니다:

스텐실 자체와 필요한 JIT README 변경 사항을 제외하면, 재현 가능한 스텐실 생성과 호스팅을 지원하기 위한 소스 코드 변경은 최소한입니다(약 150줄 변경).

기각된 아이디어

이 PEP를 위한 조사와 탐색 과정에서 여러 대안적 접근 방식을 검토했습니다. 그러나 아래의 아이디어들은 인프라 비용이나 유지 관리 부담이 따르거나, 전반적인 개발자 경험이 더 나빠집니다.

Git 하위 모듈 사용

Git 하위 모듈은 또 다른 종류의 바람직하지 않은 마찰을 일으키므로 스텐실을 호스팅하는 방식으로는 개발자 경험이 좋지 않습니다. 예를 들어, JIT를 업데이트할 때마다 스텐실을 다시 생성하여 별도의 저장소에 커밋해야 합니다. 이는 복잡한 절차를 초래합니다. 하위 모듈 저장소에서 스텐실을 갱신하고, 그 변경 사항을 커밋한 다음, 메인 CPython 저장소에서 하위 모듈 참조를 갱신해야 합니다. 이러한 단절은 불필요한 복잡성과 오버헤드를 더하여, 기여자와 유지 관리자에게 이 과정을 취약하고 오류가 발생하기 쉬운 것으로 만듭니다.

Git 서브트리 사용

서브트리를 사용하면 이 PEP에서 제안하는 방식과 비슷하게, 포함된 저장소가 메인 저장소의 일부가 됩니다. 그러나 서브트리는 유지 관리를 위해 추가 도구와 단계가 필요하므로 워크플로에 불필요한 복잡성을 더합니다.

별도의 저장소에 호스팅

JIT 스텐실을 별도의 저장소로 분리하면 스텐실 호스팅에 따르는 저장 공간 오버헤드는 피할 수 있지만, 빌드 과정은 더 복잡해집니다. 스텐실을 가져오기 위한 추가 도구가 필요하며, 이는 워크플로에 불필요한 실패 지점을 추가로 만들 수 있습니다. 또한 이렇게 분리하면 업데이트를 여러 저장소에 걸쳐 조율해야 하므로, 스텐실과 CPython 소스 트리 사이의 일관성을 보장하기가 더 어려워집니다.

클라우드 스토리지에 호스팅

S3 버킷이나 GitHub raw 스토리지 같은 클라우드 스토리지에 스텐실을 호스팅하면 외부 의존성이 생겨 오프라인 개발 워크플로가 복잡해집니다. 또한 제공업체에 따라 이러한 호스팅에는 추가 비용이 들며, 저희는 이를 피하고자 합니다.

Git LFS 사용

Git Large File Storage(LFS)는 기여자에게 도구 의존성을 추가하여, 특히 아직 Git LFS를 사용하지 않는 사람들의 개발 워크플로를 복잡하게 만듭니다. LFS로 관리되는 파일은 특정 커밋을 체크아웃할 때 가져오기 위해 인터넷 연결이 필요하므로 Git LFS는 오프라인 워크플로와 잘 맞지 않으며, 이는 가장 기본적인 Git 워크플로조차 방해합니다. Git LFS는 일정한 무료 할당량을 제공하지만, 그 할당량을 초과하면 추가 비용이 발생하며, 이 또한 바람직하지 않습니다.

LLVM을 빌드 시점 의존성으로 두는 현재 상태 유지

LLVM을 빌드 시점 의존성으로 유지하면 도입과 기여를 가로막는 기존의 장벽이 그대로 남습니다. 결국 이 방안은 접근성과 단순성이라는 핵심 과제를 해결하지 못하며, 가을에 열린 Python 코어 개발자 스프린트(이 PEP의 계기)에서 바람직하지 않다고 판단된 의존성도 제거하지 못하므로 장기적인 해결책으로는 적절하지 않습니다.

각주