47년. 컴파일러 최적화가 이 문제를 제대로 해결할 수 있었던 시간이다.
GCC의 첫 커밋은 1987년에 이루어졌다. LLVM은 2003년. 이 두 컴파일러 인프라는 프로덕션에 배포되는 사실상 모든 C, C++, Rust 코드를 처리한다. 개발자들은 최적화 다이얼을 -O3으로 올리고, 바이너리가 줄어들고 벤치마크 수치가 오르는 것을 확인한 뒤, 다음 작업으로 넘어간다. 암묵적 계약은 단순하다: 컴파일러가 당신보다 더 잘 안다.
킹스 칼리지 런던의 Laurie Tratt 연구 그룹이 발표한 두 편의 새로운 연구는 그 계약에 아무도 읽지 않는 세부 조항이 있음을 시사한다.
Tratt의 연구 그룹은 엔지니어들이 당연시하는 것을 측정했다
Tratt의 블로그에 상세히 기술된 바와 같이, 이 연구 그룹은 대부분의 현업 엔지니어가 이미 결론난 것으로 취급하는 질문을 다룬 두 편의 논문을 발표했다: -O3이 실제로 코드에 내재된 성능을 온전히 끌어내는가? 구전이 아닌 실증적 측정에 기반한 답은 명확한 '아니오'다. 그리고 그 격차는 학술적 수준이 아니라, p99 레이턴시에 그대로 나타나는 수준의 격차다.
첫 번째 연구는 순서 문제에 초점을 맞췄다. 컴파일러 최적화 패스들—데드 코드 제거, 루프 언롤링, 상수 폴딩 같은 개별 변환들—은 고정된 순서로 실행된다. 이 순서는 컴파일러 엔지니어들이 어떤 순서가 최선의 결과를 내는지에 대한 합리적 가정을 바탕으로 설계한 것이다. 연구는 동일한 패스들의 다른 순서 배치가 측정 가능할 정도로 더 빠른 바이너리를 생성할 수 있는지를 검증했다.
가능했다. 그것도 상당히.
두 번째 연구는 관련되지만 별개인 문제를 다뤘다: 기본 세트의 재배치뿐 아니라, 완전히 다른 최적화 패스 조합이 추가적인 성능 향상을 이끌어낼 수 있는지의 문제다. 여기서도 데이터는 성능에 집착하는 엔지니어들이 오래전부터 의심해온 바를 확인해주었다. 컴파일러의 기본 패스 파이프라인은 타협이다—매우 훌륭한 타협이지만, 어디까지나 타협이다.
기본값은 어떻게 고착되었나 (1987, 2003)
이것이 지금 왜 중요한지 이해하려면, 이 기본값들이 애초에 어떻게 설정되었는지를 알아야 한다.
GCC의 최적화 파이프라인은 유기적으로 진화했다. 컴파일러 연구자들이 새로운 변환을 발견할 때마다 새로운 패스가 추가되었다. 순서는 수작업으로 조율되고, SPEC CPU 같은 벤치마크 스위트를 대상으로 테스트된 후 배포되었다. 이것은 실용적인 엔지니어링이었다. 30개 이상의 최적화 패스의 모든 순열을 테스트할 수는 없다. 각 패스는 다른 패스들과 비선형적으로 상호작용할 수 있기 때문이다. 조합 공간은 말도 안 되게 거대하다.
2003년 LLVM이 등장했을 때, Chris Lattner와 그의 동료들은 백지에서 시작할 수 있다는 이점이 있었다. 더 모듈화된 패스 인프라를 설계할 수 있었다. 그러나 근본적인 제약은 그대로였다: 패스 파이프라인은 여전히 하나의 고정된 순서여야 했다. 성능 튜닝은 SPEC 벤치마크를 돌리고, 파이프라인을 조정하고, 평균적으로 가장 잘 작동하는 것을 배포하는 방식이었다.
핵심 키워드는 "평균적으로"다. 당신의 코드는 평균이 아니다.
PGO와 LTO는 잘못된 병목을 공략했다 (2010, 2020)
최적화 한계에 대한 업계의 대응은 지난 10년간 두 가지 기법에 집중되어 왔다: 프로파일 기반 최적화(PGO)와 링크 타임 최적화(LTO).
PGO는 런타임 프로파일링 데이터를 컴파일러에 피드백하여 분기 예측, 인라이닝 임계값, 코드 배치에 대해 더 나은 판단을 내리게 한다. LTO는 컴파일러의 가시 범위를 개별 번역 단위 너머로 확장하여, 링크 타임에 전체 프로그램에 걸쳐 최적화할 수 있게 해준다.
두 기법 모두 실제로 효과가 있다. PGO는 실제 워크로드에서 10~20%의 성능 향상을 이끌어낼 수 있다. LTO는 파일 단위 컴파일에서 완전히 놓치는 크로스 모듈 최적화 기회를 포착한다.
그러나 두 기법 모두 Tratt의 연구가 지적하는 근본적인 문제는 해결하지 못한다. PGO는 컴파일러에게 어떤 분기가 핫한지 알려준다. 최적화 패스가 실행되는 순서를 바꾸지는 않는다. LTO는 컴파일러가 볼 수 있는 코드의 범위를 넓혀준다. 그 코드에 대해 다른 패스 조합이 더 나은 결과를 낼 수 있는지를 탐색하지는 않는다.
둘은 서로 다른 문제를 해결하는 상호보완적 도구다. 이 연구들은 나머지 문제가 여전히 활짝 열려 있음을 보여준다.
실제 프로그램, 실제 수치, 실제 엄밀함 (2024, 2026)
Tratt 연구 그룹의 작업이 이전 컴파일러 연구와 구별되는 점은 가설이 아니다—페이즈 오더링에 대해서는 1980년대부터 알려져 있었다. 다른 점은 실증적 엄밀함과 규모다.
이 연구들은 대안적 순서가 더 나을 수 있다는 것을 단순히 입증하는 데 그치지 않는다. 실제 프로그램에 대해, 마이크로벤치마크를 괴롭히는 측정 노이즈를 고려한 통계적 방법론을 적용하여, 얼마나 더 나은지를 정량화한다. Tratt의 글에 따르면, 결과는 기본값이 아닌 패스 구성에서 일관적이고 재현 가능한 성능 향상을 보여준다. 토이 예제가 아니라 실제 코드베이스에서.
바로 이 부분이 인프라 엔지니어들이 주목해야 할 지점이다. 당신의 팀이 핫 패스를 유지보수하고 있다면—데이터베이스 엔진, 네트워크 프록시, 트레이딩 시스템, 렌더링 파이프라인—소스 레벨에서 아무리 수작업으로 튜닝해도 회복할 수 없는 성능을 테이블 위에 놓아두고 있는 것이다. 병목은 당신의 코드가 아니다. 컴파일러가 당신의 코드에 대해 가지고 있는 가정이다.
이 발견이 2026년에 더 강하게 다가오는 이유
세 가지 수렴하는 트렌드가 이 연구를 5년 전보다 훨씬 더 실행 가능하게 만든다.
첫째, 컴퓨팅 비용이 치솟고 있다. 클라우드에 배포된 모든 서비스가 사이클을 세고 있다. 사이클이 곧 비용이기 때문이다. AWS 청구서는 벤치마크 점수에 관심이 없다; 실제 워크로드의 벽시계 시간에 관심이 있다. 컴파일 출력에서 3~5%의 개선은 규모에서 직접적인 비용 절감으로 이어진다.
둘째, Rust 생태계가 LLVM의 패스 파이프라인을 그대로 물려받았다. Rust 개발자들은 C++ 개발자들보다 컴파일러를 더 신뢰하는 경향이 있는데, 언어의 안전성 보장이 컴파일러에 대한 순응 문화를 조성하기 때문이다. 그러나 rustc의 최적화 파이프라인은 *곧* LLVM의 최적화 파이프라인이다. 동일한 페이즈 오더링 한계가 적용된다. 동일한 성능 향상이 방치되고 있다.
셋째, AI 기반 코드 생성이 사람이 작성하지도, 프로파일링하지도 않을 코드로 프로덕션 시스템을 범람시키고 있다. Copilot이나 Claude가 핫 루프를 작성하고 컴파일러의 기본 파이프라인이 이를 차선으로 컴파일할 때, 이를 알아챌 사람이 아무도 없다.
실무자를 위한 행동 지침
그렇다면 이 정보를 가지고 실제로 무엇을 해야 하는가?
솔직한 답: 아직 턴키 솔루션은 없다. GCC나 Clang에 --optimize-harder를 넘길 수는 없다. 하지만 구체적인 단계는 있다.
성능이 중요한 코드를 유지보수하고 있다면, 먼저 바이너리의 실제 성능을 대안적 최적화 레벨과 비교 측정하는 것부터 시작하라. -O2와 -O3의 차이는 잘 알려져 있지만, -O3과 특정 패스를 재배치하거나 비활성화한 -O3의 차이는 프로덕션 환경에서 거의 테스트되지 않는다. Tratt의 연구는 그래야 한다고 시사한다.
LLVM의 opt 같은 도구를 사용하면 개별 최적화 패스를 커스텀 순서로 실행할 수 있다. 번거롭다. 기본 상태로는 CI에 적합하지 않다. 하지만 가장 핫한 경로에 대해서는 그 투자가 정당화될 수 있다.
더 넓은 생태계를 위해서, 진정한 기회는 컴파일러 인프라 자체에 있다. OpenTuner 같은 자동 튜닝 프레임워크와 반복적 컴파일 연구는 수년간 이 영역을 탐구해왔지만, 주류 툴체인에 편입되지는 못했다. 이 연구들은 컴파일러 메인테이너들에게 그 필요성을 주장할 수 있는 새로운 실증적 근거를 제공한다.
어셈블리로 손을 뻗기 전에, 먼저 패스 순서를 확인하라
대부분의 개발자는 컴파일러 패스를 수동으로 재배치하는 일이 없을 것이다. 괜찮다. 이 연구의 요점은 모든 엔지니어를 컴파일러 해커로 만드는 것이 아니다.
요점은 기준점 교정이다. 프로파일러를 돌려 핫 함수를 찾고, "컴파일러가 최선을 다하고 있으니, 어셈블리나 SIMD로 다시 작성해야 한다"고 결론 내릴 때, 당신이 틀렸을 수 있다. 컴파일러가 단지 당신의 특정 코드에 대해 패스를 잘못된 순서로 실행하고 있을 뿐일 수 있다. 이는 재작성보다 훨씬 저렴하게 해결할 수 있는 문제다.
Tratt의 작업은—이 글을 쓰는 시점에서 해커 뉴스에서 747 포인트를 기록하며 이미 상당한 논의를 불러일으킨 바 있다—컴파일러 연구에서 드문 성과를 대표한다: 엄밀하면서 동시에 현업 엔지니어에게 즉각적으로 관련 있는 발견. 기본 파이프라인은 좋다. 최적은 아니다. 그리고 모든 사이클에 가격표가 붙는 2026년, "충분히 좋은"은 다시 한번 점검해볼 가치가 있다.
컴파일러는 많이 안다. 하지만 프로파일러가 아는 만큼 당신의 코드를 알지는 못한다. 기본값이 아니라 데이터를 신뢰하라.