얼쑤의 Jenkins 빌드가 길어졌을 때, 저는 완료 화면의 전체 시간부터 단계별로 쪼개 봤습니다. 백엔드 빌드에서는 시작 기록이 남은 뒤 첫 단계까지 14분 넘게 걸렸고, 별도의 웹 빌드에서는 실제로 실행기에 올라간 뒤 Wasm 최적화 도중 시간 제한에 걸렸습니다. 두 경우 모두 빌드가 오래 걸렸지만, 손봐야 할 곳은 달랐습니다.
첫 단계까지의 대기 시간
빌드 기록의 시작·종료 시각을 Jenkins의 단계별 시작·종료 시각과 맞춰 봤습니다. 빌드 시작부터 첫 단계까지, 첫 단계부터 마지막 단계가 끝날 때까지, 마지막 단계 이후로 나누면 어느 구간이 길었는지 보입니다.
| 백엔드 빌드 한 건의 측정 구간 | 경과 시간 |
|---|---|
| 첫 단계 이전 | 853.945초 |
| 첫 단계부터 마지막 단계가 끝날 때까지 | 739.802초 |
| 마지막 단계 이후 | 0.363초 |
| Jenkins 표시 전체 시간 | 1594.110초 |
첫 단계 전 구간에는 파이프라인 초기화도 들어갑니다. 이 사례에서는 실행기를 기다린다는 로그가 있었고, 같은 시간대에 다른 두 잡이 공유 Linux 실행기를 차례로 사용했습니다. 두 기록을 맞춰 보고 대기가 긴 구간의 대부분을 차지한다는 판단을 내렸습니다. 빌드 번호가 생기기 전에 대기열에 머문 시간은 이 집계의 범위 밖입니다. 그래서 웹 최적화 전후를 비교할 때도 첫 단계 이후의 시간과 Jenkins 표시 전체 시간을 따로 기록했습니다.
웹 빌드의 로그는 다른 지점을 가리켰습니다. 첫 단계 전 대기가 길었던 데다, 실행을 시작하고 나서도 production Wasm 최적화가 진행되던 중 20분 실행 제한에 걸렸습니다. 로그에 남은 812.672초는 최적화를 시작하고 중단되기까지 걸린 시간입니다. 이 문제를 좁히려면 실행기 대기와 별도로, 최적화 계산에 실제로 걸리는 시간을 재야 했습니다.
Wasm 최적화만 재실행
Kotlin이 만든 production Wasm은 번들에 넣기 전에 Binaryen의 wasm-opt를 거칩니다. 같은 입력의 결과를 Gradle이 이미 갖고 있으면 이 계산을 건너뛸 수 있습니다. UP-TO-DATE는 작업공간에 유효한 출력이 있다는 판정이고, FROM-CACHE는 저장해 둔 출력을 복원했다는 판정입니다. 두 판정이 찍힌 실행의 시간은 재사용 경로에서 잰 값입니다. 새 입력을 최적화하는 비용은 실제 실행에서 따로 쟀습니다.
격리된 작업공간에서 중간 산출물을 유지하고 최적화 태스크만 다시 돌렸습니다. 이 상태라면 작업공간을 통째로 비울 때 함께 들어오는 컴파일과 테스트 비용을 비교에서 덜어낼 수 있습니다.
./gradlew :webApp:compileProductionExecutableKotlinWasmJsOptimize --rerun
첫 Optimize 태스크의 콘솔 판정과 실행 중인 wasm-opt 프로세스를 함께 확인했습니다. 후속 번들 단계에서 Optimize가 UP-TO-DATE로 나오더라도 앞 단계에서 계산을 이미 끝냈을 수 있기 때문입니다. Gradle의 개별 태스크 재실행 문서
변수 정리를 한 번으로 줄인 결과
Linux에서는 최적화 도중 코어 하나를 계속 쓰는 구간을 관찰했습니다. 어떤 변환에 시간이 걸리는지 알아보기 위해 Mac에서 Binaryen의 변환별 로그를 별도로 확인했습니다. 기본 설정의 두 번째 -O3 묶음에서 인라이닝과 로컬 변수 정리가 시간을 쓰고 있었습니다. 로컬 변수 정리는 사용 시점이 겹치지 않는 변수가 같은 슬롯을 재사용하도록 돕습니다.
기본 최적화 과정에서 로컬 변수 정리를 건너뛰고 마지막에 한 번 수행하도록 --skip-pass=coalesce-locals와 --coalesce-locals-learning을 적용했습니다. Mac에서 같은 입력과 Binaryen 130으로 옵션별 두 번씩 실행했을 때, 기본 설정은 121.466초와 135.181초, 변경한 설정은 69.910초와 66.996초였습니다. Mac의 로그는 바꿔 볼 옵션을 고르는 데 썼고, 운영 환경에서 얻을 결과는 Linux에서 별도로 확인했습니다.
최적화 도중 멈춘 다른 운영 빌드의 소스로도 바꾼 옵션을 확인했습니다. 별도 Linux 작업공간에서 중간 산출물을 재사용하고 최적화만 강제로 실행하자 최적화는 235.383초에 끝났습니다. 20분 제한을 유지한 상태에서 첫 단계부터 Chrome 화면 기동, 이미지 생성, 배포용 파일 보관까지 300.772초가 걸렸습니다.
이후 운영 빌드 두 건을 같은 Linux 실행기에서 비교했습니다. 앱 소스와 최적화 전 Wasm의 SHA-256이 같았고, 양쪽 모두 첫 Optimize 태스크에서 wasm-opt가 실제로 실행됐습니다.
| 측정 구간 | 기존 설정 | 변경한 설정 |
|---|---|---|
| Wasm 최적화 | 956.157초 | 237.163초 |
| 첫 단계부터 웹 파일 보관까지 | 1028.092초 | 321.396초 |
| 첫 단계부터 배포 완료까지 | 1076.880초 | 370.038초 |
| Jenkins 표시 전체 시간 | 1447.116초 | 724.436초 |
이 한 쌍에서 Wasm 최적화 단계는 75.2% 짧아졌고 Jenkins 표시 전체 시간은 49.9% 짧아졌습니다. 두 빌드 모두 Wasm·JavaScript 브라우저 테스트와 운영 배포를 통과했습니다. 새 옵션으로 배포한 뒤 실제 HTTPS 응답의 릴리스 표식이 배포 기록과 일치하는 것도 확인했습니다.
대신 압축 전 앱 Wasm이 8,866,072바이트에서 9,328,149바이트로 5.21% 커졌습니다. 당시 검증은 브라우저에서 앱이 뜨는 것까지였고, 실제 사용자의 다운로드와 시작 시간은 별도 측정 범위로 남았습니다.
공유 실행기에 들어가는 작업을 줄이기 위해 웹 배포를 수동으로 전환한 과정은 별도 글에 정리했습니다. 백엔드는 자동, 웹은 검증한 SHA로 배포

댓글
댓글과 반응은 GitHub 계정으로 로그인해 남길 수 있어요.