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
번역·라이선스 안내
이 비공식 한국어 번역은 원문 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를 참조하십시오).
현재 CPython을 빌드하려면 빌드 시 의존성으로 JIT requires LLVM을 사용해야 합니다. 최종 사용자에게 노출되지 않더라도 이 의존성은 최적의 방식이 아닙니다. LLVM을 요구하면 개발자와 JIT를 활성화하여 CPython을 빌드하려는 사람들에게 설정 부담이 추가됩니다. 운영 체제에 따라 해당 운영 체제와 함께 제공되는 LLVM 버전이 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배 커집니다. 그러나 이 경로를 택하게 된다면, 이러한 크기 증가를 상쇄하는 데 도움이 될 수 있는 스텐실 파일에 대한 추가 수정도 적용할 수 있습니다(예: 주석 제거, 스텐실 최소화).
사양
이 사양은 이 PEP가 승인될 경우 LLVM에 대한 빌드 시간 의존성을 제거하고 기여자 경험을 개선하기 위해 제안된 변경 사항을 설명합니다.
저장소 변경 사항
이제 CPython 저장소는 Tools/jit에 있는 stencils/라는 새 하위 디렉터리에 사전 컴파일된 JIT 스텐실을 저장합니다. 현재 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에서 생성된 스텐실을 비교하는 새로운 단계를 도입합니다. 플랫폼의 스텐실 파일에 차이가 있으면 업데이트된 스텐실에 대한 패치 파일이 생성되고 해당 단계는 실패합니다. 각 패치는 GitHub Actions에 업로드됩니다. 모든 플랫폼에서 CI 실행이 완료되면 편의를 위해 패치가 하나의 패치 파일로 통합됩니다. 이 통합 패치를 다운로드하여 로컬에서 적용한 다음 업데이트된 스텐실을 브랜치에 커밋할 수 있습니다. 그러면 이후 CI 실행이 통과합니다.
참조 구현
참조 구현의 주요 부분은 다음과 같습니다:
.github/workflows/jit.yml: 스텐실 패치를 생성하는 CI 워크플로입니다.Tools/jit/stencils: 스텐실이 저장되는 디렉터리입니다.Tools/jit/_targets: 빌드 시점에 템플릿을 컴파일하고 파싱할 코드입니다.
스텐실 자체와 필요한 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에는 일정한 무료 할당량이 있지만, 해당 할당량을 초과하면 발생하는 additional costs도 바람직하지 않습니다.
빌드 시점 의존성으로 LLVM을 사용하는 현재 상태 유지
LLVM을 빌드 시점 의존성으로 유지하면 채택과 기여를 가로막는 기존 장벽이 그대로 유지됩니다. 궁극적으로 이 선택지는 접근성과 단순성이라는 핵심 과제를 해결하지 못하며, 가을에 열린 Python 핵심 개발자 스프린트에서 바람직하지 않은 것으로 판단된 의존성(이 PEP를 추진하게 된 계기이기도 합니다)을 제거하지도 못하므로, 장기적인 해결책으로는 적절하지 않습니다.
각주
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.