메타데이터를 일찍 내보내면 Rust 빌드와 체크가 최대 두 배 빨라집니다

Emitting metadata early makes building/checking Rust up to twice as fast

github.com/PowderworksCode ▲ 127 댓글 30 knuckleheads

요약

의존 크레이트의 타입 검사가 끝나기 전에 다음 크레이트 컴파일을 시작하는 Rust 패치가 나왔습니다.

PowderworksCode가 공개한 headstart는 rustc 패치 6개와 Cargo 패치 3개로 된 실험 프로젝트입니다. 지금은 각 크레이트(Rust의 패키지 단위)가 의존하는 크레이트의 함수 본문 검사까지 끝나야 컴파일을 시작합니다.

왜 중요한가

  • 16코어 클린 빌드에서 cargo check는 최대 54%, cargo build는 최대 42% 빨라졌습니다.
  • 코어가 의존성 결과를 기다리며 놀던 구간을 메우는 방식이라, 프로젝트 코드를 고치지 않고도 병렬성이 올라갑니다.
  • 작성자는 이 패치를 rustc와 Cargo 본가에 낼 풀 리퀘스트로 다듬을 계획이라고 밝혔습니다.

핵심 내용

  • rustc가 함수의 인자·반환 타입 같은 인터페이스만 검사한 뒤 .early-rmeta(조기 메타데이터) 파일을 먼저 씁니다.
  • Cargo는 이 파일이 나오자마자 의존하는 크레이트를 시작하고, cargo check는 이것만으로 끝까지 진행합니다.
  • cargo build에서는 코드 생성 직전에 멈추고, 전체 메타데이터가 올 때까지 작업 슬롯을 다른 일에 내줍니다.
  • 함수 본문에 오류가 있으면 지금처럼 빌드가 실패하지만, 오류가 조금 늦게 뜨고 최대 메모리 사용량이 늘어납니다.
  • 4코어에서는 효과가 줄어 rust-analyzer 기준 체크가 24%, 빌드가 13~15% 빨라졌습니다.

HN 반응

  • 일부 이용자는 Rust가 2019년부터 메타데이터를 먼저 내보내는 파이프라인 빌드를 써 왔고, 이번 패치는 그 시점을 더 앞당긴 것이라고 설명했습니다.
  • 작성자는 LLM으로 짠 이 패치가 그대로 채택되지는 않겠지만 컴파일러 팀과 논의 중이라고 했고, LLM 시제품으로 아이디어를 검증하는 방식이 좋다는 의견이 이어졌습니다.

댓글

30개 표시 · 전체 30개
  1. WalterGR HN

    이 기법에 대해서는 며칠 전에 올라온 "How to speed up the Rust compiler in September 2026" 글의 댓글 스레드에 흥미로운 논의(잠재적인 단점 포함)가 있습니다: https://news.ycombinator.com/item?id=49923594

  2. aw1621107 HN

    참고로 거기서 댓글 단 사람이 이 글의 작성자입니다.

  3. kibwen HN

    잠재적인 단점과 선행 사례(약간 다른 형태로 예전에 이를 시도했던 때의 링크 포함)에 대한 추가 정보입니다: https://github.com/PowderworksCode/headstart/blob/main/docs/design.md#risks

  4. swiftcoder HN

    이게 메인라인 컴파일러에 들어갈 길이 있을지 기대되네요.

  5. knuckleheads HN

    지금 그쪽과 이야기 중입니다! 이번 변경 묶음 자체는 반영되지 않을 겁니다(LLM이 작성했고, 더 넓은 설계에 대한 고민이 거의 없었으니까요). 그래도 비슷한 것이 언젠가 들어가기를 바라고 있습니다.

  6. gchamonlive HN

    생각해 본 적 없는 관점이네요. LLM이 만든 코드가 코드베이스에 들어가지 않더라도, 그 코드가 담은 내용을 둘러싼 논의에서 얻는 게 있을 수 있다는 거잖아요.

  7. Aurornis HN

    LLM으로 프로토타입을 수십 개 만들고, 방향을 정하기 전에 전부 시험해 보는 건 LLM의 큰 강점 중 하나입니다.

    이제는 어떤 길이 성과를 낼지 짐작할 필요가 없습니다. LLM에게 전부 시험해 보게 한 다음, 가장 좋았던 걸 원하는 방식으로 직접 다시 쓰면 됩니다.

  8. knuckleheads HN

    네, 꽤 잘 생각한 정책입니다. 누군가 한 달을 들여 작업했는데 결국 코드가 거절당하면 마음이 좋지 않죠. 하지만 LLM이 가벼운 안내만 받고 며칠 만에 대충 만든 것이라면 얼마든지 좋습니다. 별난 시도를 해 보고 어떻게 되는지 확인한 다음, 될 것 같다는 확신이 서면 그때 한 달을 들여 제대로 만들면 됩니다.

  9. nonethewiser HN

    그래서 LLM이 만든 PR이 좋다는 거예요... 그냥 PR 말고 이슈로 열면 되잖아요.

  10. thayne HN

    좋은 지적입니다. 제가 참여하는 프로젝트에도 PR이 몇 건 들어왔는데, 전체적인 아이디어는 좋지만 실제 코드에 심각한 문제가 있어서 결국 아이디어만 가져다 제가 더 나은 방식으로 직접 구현했습니다.

  11. scoopr HN

    어, 저는 이런 건 이미 하고 있는 줄 알았는데, 아마 좀 더 후반 단계에서 했던 모양이네요. 멋지네요!

    이와 관련해서 샤워하다 든 생각이 있는데요. rustc가 제네릭 메서드를 인스턴스화하지 않고 대신 찾아야 할 것(std::Vec<String>::push)만 적어 두고, 별도의 빌드 프로세스가 이를 받아서 처리하되 전체 빌드에서 이미 빌드된 것은 중복해서 빌드하지 않게 할 수는 없을까요?

    보통 중복이 얼마나 되는지는 사실 모르지만, 그게 문제의 일부일 거라는 인상은 받았습니다.

    물론 저는 컴파일러 엔지니어가 아니라서, 크레이트별 빌드 프로파일 같은 복잡한 문제가 있을 거라고 생각합니다.

  12. kibwen HN

    > 저는 이런 건 이미 하고 있는 줄 알았는데

    하고 있습니다. 크레이트를 빌드할 때 Cargo는 그 크레이트의 의존성이 컴파일을 완전히 끝낼 때까지 기다릴 필요가 없고, 각 의존성이 메타데이터를 내놓을 때까지만 기다리면 됩니다. 여기 나온 프로토타입은 그 기존 구조 위에서, 타입 검사가 모두 끝나기 전에 메타데이터를 더 일찍 쓰게 만든 것입니다. 실질적인 병렬성을 높일 가능성이 있으니, 특정 크레이트 그래프에서 이점이 있을지는 컴파일 중에 코어가 이미 모두 효과적으로 쓰이고 있는지, 아니면 메타데이터가 나오기를 기다리느라 Cargo가 코어를 놀리고 있는지에 달려 있습니다.

  13. knuckleheads HN

    맞습니다. 남는 코어가 거의 없거나 서로 무관한 의존성이 아주 넓게 퍼져 있다면 대체로 아무 효과가 없습니다. 하지만 보통은 그렇지 않아서 성능 향상이 꽤 나옵니다.

  14. hmokiguess HN

    그러니까 캐시 같은 건가요? TS용 https://turborepo.dev 가 떠올랐는데, 비슷한 개념인가요?

  15. knuckleheads HN

    (rust zulip에 올린 글을 그대로 가져왔습니다)

    .early-rmeta 파일이 생성되는데, 여기에는 함수의 바깥 부분(인자, 반환값)을 타입 검사한 결과가 들어 있습니다. 이 파일을 이를 쓸 수 있는 다른 모든 의존 대상에 넘겨 주면, 그쪽에서 작업을 "먼저 시작(headstart)"할 수 있습니다. Rustc에서 이를 켜는 플래그가 -Zearly-metadata입니다. 또 진짜 메타데이터가 나오면, 그동안 쓰던 앞당겨 만든 메타데이터를 진짜로 바꿔 끼우는 법도 rustc가 배워야 했습니다.

    Rustc는 특정 지점에서 멈췄다가 다시 시작할 수 있어야 하고, Cargo는 그 지점을 찾아 대응하는 법을 알아야 하는데, Cargo 쪽에서 이를 맡는 것이 -Zheadstart입니다. 그래서 job_queue에 몇 가지 변경이 들어갑니다. 아직 직접 확인하지는 못했지만, 제가 이해하기로는 프로세스를 죽이지 않고 그냥 대기시키며, 예전 같으면 슬롯 하나를 차지했겠지만 이제는 차지하지 않습니다.

    그러니 캐시가 아니라, 작업을 멈췄다가 다시 시작할 수 있게 해서 가용 슬롯을 더 잘 활용하는 것입니다.

  16. eluusive HN

    이게 반영되면 크레이트에 메타데이터 파일을 포함시켜서, 분석 비용이 반복되는 것까지 피할 수 있다는 얘기처럼 들리는데요? TypeScript의 .d.ts 파일 같은 식으로요?

  17. knuckleheads HN

    재미있는 발상입니다. 다만 제 느낌으로는 현재 컴파일러의 방향과는 맞지 않을 것 같습니다. rmeta 파일을 비롯한 많은 Rust 산출물은 그렇게 이식할 수 있을 만큼 안정적이도록 만들어진 게 아닙니다. 그래도 한번 이것저것 해 보고 뭐라도 나오는지 보겠습니다!

  18. panstromek HN

    빌드 단위를 더 깊게 파이프라이닝하는 것입니다(CPU가 파이프라이닝하는 방식과 비슷합니다). Rust는 한동안 파이프라인 빌드를 해 왔는데, 이를 더 확장한 것입니다.

  19. boxed HN

    제가 이해한 바로는 함수의 외부 API를 믿고, 그 하위에 있는 작업을 병렬로 계속 진행하는 방식에 가깝습니다. 나중에 함수 본문이 타입 검사에 실패하면 컴파일을 중단하게 되고 그만큼 일을 헛한 셈이 되지만, 제가 알기로 그런 경우는 꽤 드뭅니다.

  20. saghm HN

    그렇게 말씀하시니 낙관적 분기 예측처럼 들리네요.

  21. hmokiguess HN

    아, 그렇군요. 그럼 비동기 타입 검사 같은 거네요.

  22. tristenharr HN

    우와, 멋진 생각이네요! :) 좋은 아이디어예요.

  23. rouanvde HN

    엄청난 개선이네요!

  24. quotemstr HN

    여담인데, 저장소를 체크인된 패치 더미로 만들어 놓은 건 그냥 우스꽝스럽습니다. 리비전 관리는 Git이 이미 해 주잖아요. 리비전 관리 안에서 또 리비전 관리를 할 필요는 없습니다.

  25. mbo HN

    동의하지 않습니다. 저는 Bazel 모노레포에서 서드파티 의존성에 패치 파일을 주입할 수 있어서 테스트가 엄청 쉬웠습니다( https://bazel.build/rules/lib/globals/module#parameters-13 ).

  26. knuckleheads HN

    그 테스트가 어떻게 됐는지 정말 궁금하니 알려 주세요!

  27. knuckleheads HN

    모든 걸 한 저장소에 두고 싶었고, 이 방식이 충분히 잘 맞았습니다. Rust 컴파일러 팀에 보여 줄 때는 해당 저장소들을 포크해서, 패치를 적용한 리뷰용 브랜치를 만들었습니다.

  28. IshKebab HN

    손쉽게 얻은 성과 같네요! 아무도 이걸 아직 안 했다니 좀 놀랍습니다. Rust의 AI 정책 때문에 누군가 이걸 손으로 다시 구현해야 하겠지만, 그래도 이게 정말 좋은 아이디어라는 걸 보여 줬다는 점에서 대단합니다.

  29. kibwen HN

    Rust는 몇 년째 이 방향으로 나아가는 중입니다. 2019년에 메타데이터를 일찍 내보내는 방식으로 파이프라이닝을 처음 도입했고( https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199 ), 그 뒤로도 메타데이터를 덜 장황하게 만들고 여러 압축 방식을 실험하는 등 여러 단계가 있었습니다. 파이프라이닝을 더 공격적으로 앞당기는 방안은 한동안 사람들이 눈여겨봐 왔고, 며칠 전 이 글의 작성자도 언급했습니다( https://news.ycombinator.com/item?id=49924257 ). 다만 추측으로 통과시킨 크레이트에서 오류가 나면 어떻게 할지에 대해서는 아직 정해야 할 결정이 남아 있습니다.

  30. IshKebab HN

    음... 오류를 내고 컴파일을 실패시키면 되잖아요? 달리 뭘 하겠어요?

    깔끔하게 처리하려면 해야 할 작업이 좀 있을 수는 있겠지만, 원하는 동작은 꽤 뻔해 보이는데요.

Hacker News에서 보기 ↗