# 작업 일지: 성능 관련 기여

일단 [rspack](https://rspack.rs/), [Lynx](https://lynxjs.org/), Lynx의 기반이 되는 [primjs](https://github.com/lynx-family/primjs)를 대상으로 골랐다. [rune](https://github.com/anomalyco/rune)에도 관심이 있었지만, GPU 기반이기도 하고 너무 초기 프로젝트 같아서 뒤로 미뤘다.

코드 변경은 전부 AI가 했다. 나는 최적화 방향을 생각하지는 않았고, 나온 변경이 옳은지만 국소적으로 리뷰했다.

셋 다 내 계정으로 포크하고, AI로 각 저장소에 Gungraun 기반 최적화 스킬을 구성했다. 포크의 CI에서 측정하고, 내 승인을 받은 변경만 원본 저장소에 PR로 보내도록 했다.

- [rspack 설정](https://github.com/kdy1/rspack/pull/3)
- [Lynx 설정](https://github.com/kdy1/lynx/pull/1)
- [primjs 설정](https://github.com/kdy1/primjs/pull/1)

결과물을 보니 벤치마크가 다 mock이었다. 프롬프트가 너무 단순했는지도 모르겠다. 그래서 모든 코드를 프로파일링할 수 있도록 다시 시켰다.

> 일단 내 포크의 Gungraun CI를 모든 걸 프로파일링 할 수 있도록 고치자

셋 다 병렬로 돌렸지만 실제 검증까지 포함이라 시간이 조금 걸렸다. primjs는 [함수 이름과 호출 비용을 확인하고, 다른 JavaScript 파일도 워크로드로 넣을 수 있도록 수정됐다](https://github.com/kdy1/primjs/pull/2).

primjs에 [첫 PR](https://github.com/lynx-family/primjs/pull/439)을 만들었다. 정수의 후위 증가·감소 연산에서 불필요한 변환을 줄이는 변경이었다.

AI를 활용해서 성능 최적화를 해도 괜찮은지 묻는 [댓글](https://github.com/lynx-family/primjs/pull/439#issuecomment-6361629024)도 남겼다. 거의 모든 작업에 AI를 쓰되, 보내는 PR은 전부 검증하겠다고 했다.

첫 PR을 보고 이 방식이 작동한다는 확신이 생겨서, 이런 기여를 받고 싶은 프로젝트가 더 있는지 [X에 물어봤다](https://x.com/kdy1dev/status/2113562240586756275). rspack 팀에도 AI로 성능에 대량으로 기여해도 되는지 물어봤고 승인을 받았다.

이 방식은 AI가 벤치마크 데이터에서 더 이상 문제를 찾지 못할 때까지 PR이 나온다. 각 PR은 깔끔하게 분리되지만 수가 많아지기 때문에, 유용한 PR을 엄청나게 많이 보내도 괜찮은지 미리 물어본 것이다.

잠깐 뒤에 primjs의 [두 번째 PR](https://github.com/lynx-family/primjs/pull/443)도 만들어졌다. 정수를 문자열로 변환할 때 기존 포매터를 재사용하는 변경이었다. PR 생성 전에 내가 변경사항을 직접 리뷰했고, 혹시 몰라 T3 Code로 보안 리뷰도 돌렸다.

> <https://github.com/lynx-family/primjs/pull/443> 가 보안상 문제가 될 수 있는지 리뷰해줘

그다음 rspack의 프로파일링 환경도 준비됐다. [기존 Rust 벤치마크 59개를 측정할 수 있도록 수정됐다](https://github.com/kdy1/rspack/pull/4).

바로 최적화를 돌렸다. rspack은 워낙 커서 프롬프트에 병렬 테스트를 추가했다.

> $gungraun-optimize 일단 프로파일링 하고, 서브에이전트로 각 최적화 아이디어를 병렬로 테스트해줘. 한번에 최대 5개까지 해주면 돼

스킬이 잘 작동하는 것 같아서 여러 프로젝트에서 쓸 수 있도록 [공통화했다](https://github.com/kdy1/kdy1-scripts/tree/8f1f49a3cee8e15357923817a4267723c0890a6b/skills/fork-gungraun-optimize). 그리고 [ada](https://github.com/ada-url/ada)에도 시도해 보려고 [포크했다](https://github.com/kdy1/ada).

primjs의 [세 번째 PR](https://github.com/lynx-family/primjs/pull/444)은 문자열 처리 중 힙 할당을 줄이는 변경이었다. 직접 리뷰해 보니 diff가 작고 범위가 명확해서 PR 생성을 승인했다.

다만 아직 Lynx 팀의 승인을 받은 것은 아니라, primjs와 Lynx에는 더 보내지 않고 이미 만든 세 개가 머지될 때까지 기다리기로 했다.

ada에도 [첫 PR](https://github.com/ada-url/ada/pull/1334)을 만들었다. 경로 인코딩 중 임시 버퍼를 없애는 변경이었다. [두 번째 PR](https://github.com/ada-url/ada/pull/1335)은 IPv6 주소를 문자열로 만들 때 불필요한 할당을 줄이는 변경이었고, diff가 작아서 리뷰하기 쉬웠다.

도메인 검증을 제거하는 변경도 나왔지만, 이게 옳은지 모르겠어서 PR 생성을 승인하지 않았다. [커밋은 포크에 남아 있다](https://github.com/kdy1/ada/commit/733effea3ae0d91fd5b93111e4c8bef3da7ae91d).

그다음에는 [문자열 검색을 단순화하는 PR](https://github.com/ada-url/ada/pull/1336)을 하나 더 만들었다. 리뷰해 보니 변경이 깔끔했고, 모든 측정 케이스에서 명령어 수가 같거나 줄어서 승인했다.

잠깐 놀다가 왔더니 ada의 [#1335](https://github.com/ada-url/ada/pull/1335)가 머지돼 있었다.

다른 두 PR에는 Codspeed에서 리그레션이 표시됐다. 확인해 보니 느려졌다고 나온 벤치마크는 변경한 경로를 실행하지 않았고, 서로 다른 종류의 러너에서 비교됐다는 경고도 있었다. 각각 [댓글](https://github.com/ada-url/ada/pull/1334#issuecomment-6366186045)을 [남겼다](https://github.com/ada-url/ada/pull/1336#issuecomment-6366189700). 보기에도 관련 없어 보였지만 확실히 하려고 AI로도 한 번 더 검증했다.

rspack 쪽에서는 swc-next를 수정할 필요가 있어서 [PR](https://github.com/swc-project/swc-next/pull/1116)을 만들었다. SIMD 마스크 변환에서 불필요한 연산을 줄이는 변경이었다.

스킬의 성능 기준은 1%인데, rspack 같은 프로젝트에서 국소적인 최적화로 전체가 1% 개선되길 바라는 건 지나친 욕심 같았다. 그래서 후보를 각각 다시 물어보라고 했다.

그 뒤 rspack에 [경로 처리 중 불필요한 문자열 검색을 피하는 PR](https://github.com/web-infra-dev/rspack/pull/16223)과 [작은 export 목록의 조회 방식을 바꾸는 PR](https://github.com/web-infra-dev/rspack/pull/16224)을 만들었다.
