<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Build Performance on jyukki's Blog</title><link>https://jyukki.com/tags/build-performance/</link><description>Recent content in Build Performance on jyukki's Blog</description><generator>Hugo -- 0.147.0</generator><language>ko-KR</language><lastBuildDate>Thu, 01 Oct 2026 10:06:00 +0900</lastBuildDate><atom:link href="https://jyukki.com/tags/build-performance/index.xml" rel="self" type="application/rss+xml"/><item><title>2026 개발 트렌드: Rust 컴파일러 성능 개선을 CI 변경 예산으로 바꾸는 법</title><link>https://jyukki.com/posts/2026-10-01-rust-compiler-performance-ci-change-budget-trend/</link><pubDate>Thu, 01 Oct 2026 10:06:00 +0900</pubDate><guid>https://jyukki.com/posts/2026-10-01-rust-compiler-performance-ci-change-budget-trend/</guid><description>최근 Rust 컴파일러 성능 개선 흐름을 단순한 언어 벤치마크가 아니라 PR 피드백 시간·CI 용량·검증 범위를 관리하는 변경 예산 관점에서 해석합니다.</description><content:encoded><![CDATA[<p>Rust 컴파일러 팀의 9월 성능 정리는 LLVM 업그레이드, trait·borrow checking, 증분 데이터 처리 등 여러 개선이 실제 crate별 compile 시간을 바꿀 수 있음을 보여줬습니다. 일부 outlier crate에서는 큰 폭의 개선도 관찰됐지만, 이 숫자를 &ldquo;우리 CI가 같은 비율로 빨라진다&quot;고 읽으면 곤란합니다. workspace 구조, feature flag, proc macro, linker, target, container image, cache, runner 대기열이 다르면 병목 위치도 달라지기 때문입니다.</p>
<p>그럼에도 이 흐름이 중요한 이유는 분명합니다. 빌드 시간은 로컬 개발자의 불편이 아니라 <strong>변경을 얼마나 자주, 얼마나 작은 단위로, 얼마나 충분히 검증할 수 있는가를 제한하는 운영 용량</strong>입니다. PR이 20분 뒤에야 첫 신호를 주면 개발자는 변경을 묶고, 리뷰어는 큰 diff를 받고, 실패한 뒤의 원인 분리는 늦어집니다. 이 글은 2026년 9월 30일 Rust 컴파일러 성능 보고를 출발점으로, <a href="/posts/2026-03-23-hermetic-build-remote-cache-trend/">Hermetic Build와 Remote Cache</a>, <a href="/posts/2026-06-25-code-quality-policy-gate-trend/">Code Quality Policy Gate</a>, <a href="/posts/2026-08-12-typescript-compiler-support-window-sdk-upgrade-contract-trend/">TypeScript 지원 기간과 SDK 업그레이드 계약</a>, <a href="/learning/deep-dive/deep-dive-ci-cd-github-actions/">CI/CD와 GitHub Actions</a>을 하나의 변경 예산으로 연결합니다.</p>
<p>공식 근거는 <a href="https://nnethercote.github.io/2026/09/30/how-to-speed-up-the-rust-compiler-in-september-2026.html">Rust 컴파일러의 2026년 9월 성능 정리</a>와 <a href="https://goals.rust-lang.org/2026/compiler-performance-optimization.html">Rust compiler performance optimization 목표</a>를 확인했습니다. 아래 숫자는 특정 프로젝트의 벤치마크 결과가 아니라, 팀이 측정을 시작할 때 사용할 수 있는 운영 기준선입니다.</p>
<h2 id="이-글에서-얻는-것">이 글에서 얻는 것</h2>
<ul>
<li>컴파일러 성능 개선을 언어 선택 논쟁이 아니라 CI 처리량과 변경 안전성 관점에서 해석할 수 있습니다.</li>
<li>clean build, incremental build, test compile, link, cache restore, queue time을 분리해 병목을 찾는 방법을 배웁니다.</li>
<li>cache를 켜기 전에 재현성·격리·무효화·fallback을 결정하는 기준을 얻습니다.</li>
<li>빠른 빌드를 더 많은 검증으로 환원하는 rollout과 체크리스트를 정리합니다.</li>
</ul>
<h2 id="핵심-개념이슈">핵심 개념/이슈</h2>
<h3 id="1-빌드-시간은-하나의-숫자가-아니라-여섯-개의-대기-시간이다">1) 빌드 시간은 하나의 숫자가 아니라 여섯 개의 대기 시간이다</h3>
<p>&ldquo;CI가 18분 걸린다&quot;는 측정만으로는 무엇을 고쳐야 할지 알 수 없습니다. 동일한 18분도 source compile이 느린 경우, test binary link가 느린 경우, cache가 빗나간 경우, runner가 비어 있지 않아 기다린 경우의 해법은 전혀 다릅니다. 최소한 아래 시간을 분리해 수집해야 합니다.</p>
<table>
  <thead>
      <tr>
          <th>구간</th>
          <th>질문</th>
          <th>우선 대응</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>queue</td>
          <td>runner를 기다렸는가</td>
          <td>병렬도·우선순위·예약 용량</td>
      </tr>
      <tr>
          <td>dependency restore</td>
          <td>artifact를 받았는가</td>
          <td>cache key·네트워크·압축 방식</td>
      </tr>
      <tr>
          <td>clean compile</td>
          <td>아무 cache 없이 얼마나 걸리는가</td>
          <td>crate 구조·compiler·codegen 병목</td>
      </tr>
      <tr>
          <td>incremental compile</td>
          <td>작은 수정이 얼마나 빨리 돌아오는가</td>
          <td>invalidation 범위·feature flag·proc macro</td>
      </tr>
      <tr>
          <td>test/link</td>
          <td>컴파일 뒤 무엇이 오래 걸리는가</td>
          <td>link 전략·test sharding·실행 환경</td>
      </tr>
      <tr>
          <td>publish/image</td>
          <td>산출물을 조립하고 검증하는가</td>
          <td>layer cache·SBOM·signing 경로</td>
      </tr>
  </tbody>
</table>
<p>Rust의 compiler 개선은 이 중 clean 또는 incremental compile을 줄일 수 있습니다. 하지만 proc macro 하나의 광범위한 invalidation, 느린 linker, 매번 바뀌는 container base image, 독점된 runner queue는 다른 층의 문제입니다. 전체 시간이 20% 줄었어도 queue가 10분이면 개발자가 느끼는 p95는 거의 변하지 않을 수 있습니다. 따라서 release note를 본 직후의 첫 일은 compiler upgrade가 아니라 <strong>시간 분해와 기준선 고정</strong>입니다.</p>
<h3 id="2-빨라진-빌드는-검증을-줄일-명분이-아니라-늘릴-여유다">2) 빨라진 빌드는 검증을 줄일 명분이 아니라 늘릴 여유다</h3>
<p>팀이 build를 빠르게 만들고도 CI timeout을 그대로 두고, 큰 PR을 계속 허용하고, critical test를 nightly에만 남기면 성능 이득은 대기 시간 감소로 끝납니다. 더 좋은 사용법은 남은 시간을 변경 위험을 줄이는 데 배정하는 것입니다. 예를 들어 PR의 fast lane이 15분 안에 끝나면 lint·type check·unit·핵심 contract test를 묶고, 느린 integration·cross-target·fuzz는 merge queue 또는 nightly로 나눌 수 있습니다.</p>
<p>다만 &ldquo;15분&quot;은 보편적 목표가 아닙니다. 작은 서비스는 5분, 모노레포의 clean build는 30분일 수 있습니다. 중요한 것은 팀이 다음 세 수치를 함께 약속하는 일입니다.</p>
<ul>
<li>developer-facing fast lane p95: 예를 들어 <strong>15분 이하</strong></li>
<li>main branch의 필수 검증 성공률: flaky retry를 숨기지 않은 상태로 <strong>98% 이상</strong></li>
<li>critical path 변경의 rollback 가능한 단위: 되돌림 PR이 <strong>하나의 배포 창</strong> 안에 검증될 수 있는 크기</li>
</ul>
<p>build가 빨라졌는데 PR이 더 커지기만 하면 품질은 좋아지지 않습니다. 반대로 fast lane이 안정되면 diff 크기, reviewer SLA, merge queue 정책을 조정할 근거가 생깁니다. 이 관점은 <a href="/learning/deep-dive/deep-dive-build-tooling-gradle-maven/">빌드 도구 Gradle·Maven</a>의 build cache 논의와도 같습니다. 속도 자체가 목적이 아니라 더 짧은 피드백 루프를 안전하게 운영하는 것이 목적입니다.</p>
<h3 id="3-cache-hit-rate는-결과-지표일-뿐-신뢰-경계는-아니다">3) cache hit rate는 결과 지표일 뿐, 신뢰 경계는 아니다</h3>
<p>원격 cache는 의존성 compile과 중간 artifact를 재사용해 CI 비용을 줄일 수 있지만, 아무 artifact나 받아 쓰는 경로가 되면 빌드 재현성과 공급망 신뢰를 약화시킬 수 있습니다. cache key에 lockfile만 넣고 compiler version, target triple, feature set, build script 입력, 환경 변수, native library 버전을 빼면 &ldquo;적중&quot;은 했지만 틀린 산출물을 가져올 수 있습니다.</p>
<p>권장 기준은 다음과 같습니다.</p>
<ol>
<li>cache write는 protected branch 또는 검증된 CI identity로 제한한다.</li>
<li>key에는 compiler·target·lockfile·feature·build script 입력을 포함하고, 누락할 수 있는 환경 값은 명시적으로 deny/allow 한다.</li>
<li>cache miss는 느려도 정상 build로 fallback해야 하며, cache 서비스 장애가 deploy 차단으로 번지지 않게 한다.</li>
<li>release 후보와 보안 민감 변경은 cache 결과에만 의존하지 않고 주기적인 clean, hermetic build와 artifact digest 대조를 한다.</li>
</ol>
<p>cache hit rate가 90%여도 wrong hit가 한 번 나면 얻은 시간을 모두 잃을 수 있습니다. 그래서 cache 성공률과 함께 fallback 성공률, restore 실패율, clean build 결과와 cache build 결과의 digest 차이, stale artifact 의심 건수를 봐야 합니다. 성능 회귀를 줄이려다 correctness 회귀를 만드는 것은 가장 비싼 최적화입니다.</p>
<h2 id="실무-적용">실무 적용</h2>
<h3 id="1-첫-2주-개선-전후를-같은-조건에서-비교한다">1) 첫 2주: 개선 전후를 같은 조건에서 비교한다</h3>
<p>compiler 또는 CI image를 바꾸기 전에 대표 workspace 3개를 고릅니다. 작은 crate, 의존성이 많은 service, integration test가 무거운 service가 좋습니다. 각 대상에서 clean build, 한 파일 수정 뒤 incremental build, test compile, test execution을 분리하고, 같은 runner image·target·feature flag·cache mode로 최소 20회 측정합니다. 평균보다 p50·p95·최장값과 queue time을 보관해야 burst나 cache eviction을 놓치지 않습니다.</p>
<table>
  <thead>
      <tr>
          <th>항목</th>
          <th>기준선</th>
          <th>candidate</th>
          <th>통과 조건</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>fast lane p95</td>
          <td>현재값</td>
          <td>compiler/image 변경 후</td>
          <td>10% 이상 악화 금지</td>
      </tr>
      <tr>
          <td>clean build p50</td>
          <td>현재값</td>
          <td>동일 runner에서 비교</td>
          <td>5% 이상 개선 또는 원인 기록</td>
      </tr>
      <tr>
          <td>incremental p95</td>
          <td>현재값</td>
          <td>실제 작은 diff 기준</td>
          <td>fast lane 목표 안</td>
      </tr>
      <tr>
          <td>cache restore 실패율</td>
          <td>현재값</td>
          <td>변경 후</td>
          <td>0.5% 미만</td>
      </tr>
      <tr>
          <td>필수 test flaky rate</td>
          <td>현재값</td>
          <td>변경 후</td>
          <td>2% 미만, 상승 시 확대 중단</td>
      </tr>
  </tbody>
</table>
<p>숫자가 기대와 다르면 compiler를 되돌리기 전에 구간을 다시 봅니다. clean build는 빨라졌는데 link가 늘었는지, cache key가 너무 넓어졌는지, runner image가 다른 native toolchain을 받는지 분류해야 합니다. 한 번의 speedup을 전체 원인으로 착각하지 않는 것이 platform 팀의 역할입니다.</p>
<h3 id="2-rollout은-전체-ci가-아니라-위험도별-lane에서-시작한다">2) rollout은 전체 CI가 아니라 위험도별 lane에서 시작한다</h3>
<p>candidate toolchain은 문서 build나 low-risk crate부터 5% canary로 적용합니다. 그 다음 non-critical service, 마지막으로 release·security path로 넓힙니다. 변경에는 compiler version, base image digest, cache namespace, rollback revision을 함께 기록합니다. 이 네 값 중 하나라도 빠지면 &ldquo;어제보다 빨랐다&quot;는 관찰을 재현할 수 없습니다.</p>
<p>초기 48시간 동안은 build 성공률, p95 duration, cache restore error, linker error, test flaky rate, queued job 수를 기존 lane과 나란히 봅니다. candidate가 빠르더라도 failed build가 0.5%p 늘거나 p95가 10% 이상 나빠지면 확대를 멈춥니다. 특히 cross compilation과 generated code는 일반 crate보다 toolchain 차이에 민감할 수 있으므로 별도 fixture가 필요합니다.</p>
<h3 id="3-성능-이득을-개발-정책에-연결한다">3) 성능 이득을 개발 정책에 연결한다</h3>
<p>fast lane이 안정되면 다음 행동을 한 번에 모두 강제하지 말고 하나씩 올립니다. 첫 주에는 변경 파일 기준 test 선택을 추가하고, 다음 주에는 critical module의 contract test를 required로 만들고, 그 다음에야 timeout이나 PR size guide를 조정합니다. <a href="/posts/2026-06-25-code-quality-policy-gate-trend/">Code Quality Policy Gate</a>처럼 warn → evaluate → enforce 순서가 안전합니다.</p>
<p>이때 확인할 질문은 &ldquo;컴파일이 얼마나 빨라졌나&quot;가 아니라 &ldquo;더 빠른 피드백으로 어떤 실패를 merge 전에 잡았나&quot;입니다. fast lane으로 이동한 test 수, 실패를 발견한 시점, revert까지 걸린 시간, CI queue 감소를 월 단위로 비교하면 성능 투자가 실제 변경 안전성으로 이어졌는지 보입니다.</p>
<h2 id="트레이드오프주의점">트레이드오프/주의점</h2>
<ol>
<li><strong>벤치마크 개선률은 workload별로 다르다.</strong> compiler report의 outlier 개선을 조직의 CI SLA로 약속하면 안 된다.</li>
<li><strong>incremental build는 빠르지만 숨은 입력에 민감하다.</strong> build script, proc macro, feature flag, 생성 파일이 cache invalidation 경계를 넓힐 수 있다.</li>
<li><strong>remote cache는 성능 계층이지 신뢰 원천이 아니다.</strong> write 권한, key 완전성, digest 검증, clean fallback이 없으면 잘못된 artifact를 빠르게 퍼뜨린다.</li>
<li><strong>parallelism은 queue를 줄일 수 있지만 비용과 shared-resource 경합을 키운다.</strong> runner 수를 늘리기 전 CPU throttling, network, registry rate limit, test DB 격리를 확인한다.</li>
<li><strong>빠른 lane과 완전한 lane을 혼동하지 않는다.</strong> fast lane은 빠른 결정용이고, release proof에는 hermetic build·보안 검사·cross-target 검증이 여전히 필요할 수 있다.</li>
</ol>
<h2 id="체크리스트-또는-연습">체크리스트 또는 연습</h2>
<h3 id="운영-체크리스트">운영 체크리스트</h3>
<ul>
<li><input disabled="" type="checkbox"> CI duration을 queue, restore, clean compile, incremental compile, test/link, publish로 분해한다.</li>
<li><input disabled="" type="checkbox"> compiler·runner image·target·feature·cache mode를 포함한 기준선이 있다.</li>
<li><input disabled="" type="checkbox"> candidate toolchain은 5% canary와 48시간 비교를 거쳤다.</li>
<li><input disabled="" type="checkbox"> cache write 권한, key 입력, 정상 fallback, clean-build 검증 경로가 있다.</li>
<li><input disabled="" type="checkbox"> fast lane p95, cache restore error, flaky rate, queued jobs의 중단 기준을 정했다.</li>
<li><input disabled="" type="checkbox"> 성능 이득으로 추가할 검증 항목과 rollout 순서가 문서화됐다.</li>
<li><input disabled="" type="checkbox"> release path는 cache 여부와 무관하게 artifact digest와 재현성 증거를 남긴다.</li>
</ul>
<h3 id="연습">연습</h3>
<p>최근 20개 PR의 CI 기록에서 가장 오래 걸린 job 하나를 골라 queue·restore·compile·link·test 시간을 나눠 보세요. 그 뒤 작은 Rust 파일 수정 1회와 dependency 변경 1회를 각각 실행해 invalidation 범위를 비교합니다. 마지막으로 fast lane이 20% 빨라졌다고 가정하고, 그 시간을 사용해 required로 올릴 contract test 하나와 nightly에 남길 expensive test 하나를 정하세요. 속도 개선을 &ldquo;대기 감소&quot;가 아니라 &ldquo;검증 재배치&quot;로 표현할 수 있으면 실무 변화가 시작된 것입니다.</p>
<h2 id="관련-글">관련 글</h2>
<ul>
<li><a href="/posts/2026-03-23-hermetic-build-remote-cache-trend/">Hermetic Build와 Remote Cache</a></li>
<li><a href="/posts/2026-06-25-code-quality-policy-gate-trend/">Code Quality Policy Gate</a></li>
<li><a href="/posts/2026-08-12-typescript-compiler-support-window-sdk-upgrade-contract-trend/">TypeScript 지원 기간과 SDK 업그레이드 계약</a></li>
<li><a href="/learning/deep-dive/deep-dive-ci-cd-github-actions/">CI/CD와 GitHub Actions</a></li>
<li><a href="/learning/deep-dive/deep-dive-build-tooling-gradle-maven/">빌드 도구 Gradle·Maven</a></li>
</ul>
]]></content:encoded></item></channel></rss>