2026년 7월 기준 Rust 컴파일러 성능 개선 사항을 rustdoc, Clippy, 증분 컴파일, 새 트레이트 솔버 등을 중심으로 살펴봅니다.
제 지난 글에서 Rust 컴파일러의 성능을 다룬 것은 2025년 12월이었습니다. 그 이후 어떤 일이 있었는지 살펴보겠습니다.
2025-12-03부터 2026-07-29까지의 측정 결과는 여기에서 볼 수 있습니다.
평균 벽시계 시간 감소율은 양호한 5.59%였습니다. 이 가운데 약 절반은 최근 rustdoc에 적용된 대규모 개선 덕분으로, rustdoc의 평균 벽시계 시간은 37.92% 감소했습니다! rustdoc 변경을 제외하면 평균 벽시계 시간 변화는 2.90%였으며, 이 역시 좋은 결과입니다. 또한 현재 CI에서 rustc-perf가 측정하지 않는 Clippy 속도에도 몇 가지 큰 개선이 있었습니다. (이에 대해서는 아래에서 더 다룹니다.)
#159623, #159721, #159779, #159854: 이 PR들에서 Noah Lev는 impl 처리 시 수행하는 작업량을 크게 줄였습니다. 그가 정확히 무엇을 했는지는 저도 그 이상 자세히 아는 척하지 않겠습니다(약간의 배경은 여기를 참조하세요). 하지만 그 결과 벽시계 시간이 두 자릿수 및 한 자릿수 퍼센트만큼 줄어든 사례가 많았다는 것은 압니다. Guillaume Gomez는 말했습니다. “누군가 rustdoc 사용 중 이상한 버그를 만난 것만으로 이 모든 일이 일어났다.”
#159091: 이 PR에서 Jakub Beránek은 rustdoc 벤치마크를 PGO 훈련 집합에 추가하여, rustdoc이 PGO의 이점을 더 많이 얻을 수 있게 했습니다. 그 결과 모든 rustdoc 벤치마크에서 평균 벽시계 시간이 2.85% 감소했고, 가장 큰 감소폭은 6%를 넘었습니다. PGO는 설정이 까다롭지만 실제로 큰 차이를 만들 수 있으며, 훈련 집합도 중요합니다.
#157179: 이 PR에서 저는 rustdoc이 impl을 정렬하는 방식을 바꿨습니다. 이전에는 impl 이름을 포함하는 긴 생성 HTML 문자열을 정렬했지만, 이제는 훨씬 짧은 impl 이름의 텍스트 표현을 정렬 키로 사용합니다. 이로 인해 여러 벤치마크에서 명령어 수가 줄었으며, 가장 좋은 경우에는 6%를 넘었습니다.
이러한 개선의 결합 효과는 아래의 모든 rustdoc 벤치마크 상대 벽시계 시간 그래프에서 볼 수 있습니다.

28% 감소입니다!
#2515: 다른 이야기로, 이 PR에서 Jakub은 rustc-perf에 rustdoc-json 벤치마킹을 활성화했습니다. 이는 cargo-semver-checks처럼 rustdoc의 JSON 출력을 사용하는 도구의 속도에 도움이 될 것입니다.
#17124, #17132: 이 두 PR에서 xmakro는 Clippy를 크게 가속했습니다. Clippy는 수백 개의 개별 린트로 구성되며, 각 린트는 수십 가지 방문자 메서드 중 하나 이상을 구현할 수 있습니다. check_item, check_stmt, check_expr 등이 그렇습니다. Clippy는 AST와 HIR을 순회하며, 각 노드마다 그 노드의 모든 린트에 대해 적절한 check_foo 메서드를 호출합니다. 각 호출은 가상 디스패치입니다. 결정적으로, 대부분의 린트는 소수의 check_foo 메서드만 구현하기 때문에(흔히 하나만 구현합니다) 이 호출 대부분은 아무 작업도 하지 않습니다. 이 PR들에서 xmakro는 패스를 결합하여 비어 있는 check_foo 메서드, 즉 압도적 다수를 호출하지 않는 방법을 찾아냈습니다.
거의 같은 시기에 저도 정확히 같은 문제를 조사하고 있었고, #157762에서 약간 다른 해결책을 생각해 냈습니다. 제 해결책은 기능적으로 동등했지만, 코드 변경은 xmakro의 것보다 덜 우아하고 더 침습적이었습니다. PR은 병합되지 않았지만, 더 자세한 측정 결과를 얻을 수 있었습니다. 대부분의 경우 Clippy의 실행 시간이 10~30% 줄었습니다! 실제 사례에서 분기 예측 실패는 20~80% 감소했고, 한 스트레스 테스트에서는 97% 감소했습니다. 가상 디스패치는 많이 수행하면 비용이 누적됩니다.
제가 Rust 컴파일러 성능을 다룬 지 10년이 되었지만, Clippy 최적화를 시도한 것은 이번이 처음이었습니다. 큰 성능 문제를 찾아 고쳤는데, 며칠 차이로 다른 누군가가 이미 저를 앞질렀다는 사실을 알게 되었습니다. 더 나은 해결책이 병합되었으니 슬프지는 않지만, 여전히 놀랍습니다. 그럴 확률이 얼마나 될까요?
증분 컴파일에도 여러 작은 개선이 있었습니다.
#153122: 이 PR에서 Zalathar는 증분 컴파일이 디스크 캐시 값을 메모리로 승격하는 방식을 개선하여 많은 벤치마크에서 명령어 수를 줄였고, 가장 좋은 경우에는 6% 감소했습니다.
#153521: 이 PR은 Zalathar가 증분 컴파일에 가한 또 다른 조정으로, 많은 벤치마크에서 명령어 수를 줄였으며 가장 좋은 경우에는 2%를 넘게 감소했습니다.
#154304: 이 PR에서 zetanumbers는 typeck 쿼리의 작동 방식을 조정하여 여러 벤치마크에서 명령어 수를 줄였고, 가장 좋은 경우에는 6% 감소했습니다.
#157781: 이 PR에서 xmakro는 많은 벤치마크에서 명령어 수를 줄이기 위해 증분 컴파일을 조정했고, 가장 좋은 경우에는 5% 감소했습니다.
#158794: 이 PR에서 xmakro는 dep 그래프 읽기 중복 제거를 개선하여 여러 벤치마크에서 명령어 수를 줄였고, 가장 좋은 경우에는 10% 감소했습니다.
#159115: 이 PR에서 xmakro는 다시 dep 그래프 읽기 중복 제거를 개선하여 많은 벤치마크에서 명령어 수를 줄였고, 가장 좋은 경우에는 6% 감소했습니다.
새 트레이트 솔버를 출시 준비 상태로 만들기 위한 많은 작업이 진행 중입니다. 여기에는 성능 작업도 포함됩니다. 많은 일이 벌어지고 있고 저는 그 대부분을 알지 못하지만, 더 알아보거나 도움을 주고 싶다면 이 Zulip 스레드가 읽기 좋은 곳입니다.
다음 이미지는 새 솔버 벤치마크 하나의 진전을 보여 줍니다.

맞습니다. 지난 석 달 동안 이 벤치마크의 벽시계 시간은 27초에서 1초 미만으로 떨어졌습니다.
#160005: 재미있어서 이것은 언급하겠습니다. lcnr은 새 트레이트 솔버가 매우 큰 성능 저하를 일으키는 몇몇 크레이트를 가리켰습니다. 저는 Cachegrind로 rustc가 그것들을 컴파일하는 과정을 프로파일링했고, 시간의 거의 절반이 memcpy에 쓰인다는 것을 발견했습니다! 이는 매우 이례적이지만, 발생할 때 DHAT의 복사 프로파일링은 믿을 수 없을 만큼 유용합니다. 요소 유형 크기가 136바이트인 뜨거운 벡터가 있었습니다. LLVM은 크기가 128바이트보다 큰 값을 이동할 때 생성된 명령어 대신 memcpy를 사용합니다. 이 PR에서 저는 (a) 이동의 2/3를 피했고, (b) 나머지 이동에는 memcpy가 사용되지 않도록 유형 크기를 104바이트로 줄였습니다. 그 결과 가장 나빴던 두 크레이트의 벽시계 시간이 40% 감소했습니다.
최근 수행되는 성능 작업량이 반갑게 증가했으며, 두 명의 새 기여자를 강조하고 싶습니다. 첫 번째는 위에서 네 번 언급한 xmakro입니다. 두 번째는 속도에 초점을 맞춘 실험적 Rust 컴파일러 Krabby의 제작자인 arya dradjica입니다. arya는 이제 Krabby와 rustc 모두에서 작업할 재정 지원을 받고 있습니다. arya의 rustc 작업은 현재 매크로 확장에 집중되어 있으며, 그 분야에서 이미 몇 가지 작은 성능 개선을 이루었습니다(예: #158976, #158974, #158577). 또한 더 많은 개선을 위한 아이디어도 갖고 있습니다. 얼마나 최적화를 좋아하는지 알고 싶다면 최근 RustWeek 발표를 확인해 보세요. (스포일러: 아주 많이 좋아합니다.)
정말 많은 관심을 받고 있지요? 아무튼, 그 이야기는 이쯤 하겠습니다.
#158942: 이 PR에서 저는 필드를 제거하여 일부 AST 노드의 크기를 줄였습니다. 제거된 데이터는 필요할 때 이제 임시로 별도 위치에 저장됩니다. 그 결과 명령어 수가 대부분 1% 미만으로 감소했습니다.
#158720: 이전 PR은 이 PR의 길을 열었으며, 이 PR에서 저는 AST 표현식 노드의 크기를 72바이트에서 64바이트로 줄였습니다. (캐시 라인에 들어갈 만큼 작습니다.) 표현식은 단연 가장 흔한 AST 노드 종류이며, 이 변경은 AST 비중이 높은 소수의 벤치마크에서 벽시계 시간을 줄였습니다. 일부는 10%를 넘게 감소했습니다. 같은 벤치마크에서 캐시 미스 비율은 최대 29%까지 떨어졌습니다. 몇 년 전 AST 표현식 노드가 104바이트였던 때가 기억납니다. 좋은 성능은 오랜 기간 조금씩, 조금씩, 조금씩 문제를 깎아 내는 데서 나오는 경우가 많습니다.
#159266: 이 PR에서 저는 속성의 AST 표현 방식을 전면 개편했습니다. 주로 코드 정리를 의도했지만, 명령어 수가 일부 1% 미만으로 감소하는 결과도 있었습니다.
#155678: 이 PR에서 aerooneqq는 여러 HIR 수준 쿼리를 하나로 병합하여 많은 벤치마크에서 명령어 수를 줄였고, 가장 좋은 경우에는 거의 3% 감소했습니다.
주간 성능 트리아지를 교대로 맡는 분들을 언급하고 싶습니다. 이 작업은 지난주에 병합되어 성능에 영향을 준 모든 PR을 살펴보고(좋은 영향과 나쁜 영향을 모두 포함), 성능 회귀를 분리하고 수정하는 데 도움이 되는 추가 정보를 수집하는 일을 포함합니다. 화려하지 않은 반자동 작업이고 완전히 자동화할 수 있을 것처럼 보일 수도 있지만, 사람이 관여하는 것이 중요하다고 생각합니다.
왜일까요? 벤치마크 모음은 크고 복잡하며, 측정값이 항상 정확하지는 않고, 사람의 개입은 설득력이 있을 수 있기 때문입니다. PR 작성자가 봇으로부터 “이 PR로 인해 아홉 개 벤치마크에서 회귀가 발생했습니다”라는 메시지를 받는 것과, 해당 분야 전문성을 갖춘 사람으로부터 “처음 네 개는 최근 그 벤치마크들이 잡음이 많았으니 무시해도 됩니다. 다음 세 개는 회귀가 너무 작아 의미 없으니 무시해도 됩니다. 하지만 마지막 두 개는 실제로 유의미하므로 살펴봐야 합니다. $REASON 때문에 발생했을 수 있는데, 이를 완화할 방법에 대한 아이디어가 있나요?”라는 메시지를 받는 것은 매우 다릅니다.
그러므로 현재 트리아지 팀인 Mark Rousskov, Jonathan Brouwer, Matyáš Racek, Jakub Beránek에게 감사드립니다. (체코인 비율 50%는 발음 구별 기호를 통해 알 수 있습니다.) 그리고 이전 트리아지 팀원인 Felix Klock, Dylan MacKenzie, Ryan Levick에게도 감사드립니다.
개인적인 소식입니다. 저는 최근 VectorWare에서 일을 그만두었습니다. 극적인 일은 없었습니다. 그저 저에게 잘 맞는 곳이 아니었습니다. 이제 Rust 컴파일러 작업으로 다시 보수를 받을 기회를 찾고 있습니다. 행운을 빌어 주세요!