사이드 프로젝트 6주 만에 v0.5 release하고 잠시 쉽니다

사이드 프로젝트 6주 만에 v0.5 release하고 잠시 쉽니다

오늘 아침 출근길에 갑자기 그런 생각이 들었어요. “이거 슬슬 마무리할 때인가.” 6주 동안 매일 1~2시간씩 노트북 열어서 짠 사이드 프로젝트가 v0.5까지 왔는데, 최근 1주는 짠 코드가 회귀 → 임시 fix → 결국 같은 자리. 진척은 있는데 호흡이 무거워진 거예요.

측정-주도 의사결정 11번을 반복하면서 얻은 결론이 사실은 단순했어요. 사이드 프로젝트로 ggml(전 세계 표준 LLM 추론 도구)이랑 같은 차원에서 경쟁하면 11번 시도해서 win 2번이 정직한 비율이에요. 그 위에 더 갈 수 있지만 호흡이 다시 좋아질 때까지 잠시 쉬려고 해요. v0.5.0 release tag 박고 정리합니다.

이건 마무리 글이에요. 5/18 AVX-512 ZMM 후기, 5/20 prefill batching 후기에 이어서 시리즈 마지막 편. 6주 동안 가설 11번 세웠는데 몇 번 부정당했고, 그 패턴 자체가 사이드 프로젝트의 본질이라는 생각을 정리해 봤어요.

한눈에 보기

  • v0.4.0 → v0.5.0: ggml 격차 1.376배 → 1.304배로 좁힘 (8 스레드)
  • 의외의 발견: 단일 스레드에서 Lumen이 ggml보다 +13% 빠름 (마이크로커널은 우리가 우세)
  • 측정-주도 사이클 11회: 명확한 가속 2회 + 진단 확정 1회 + 회귀/부정 8회
  • 인프라 폐기 0개 — 모든 부정된 시도는 default-off 상태로 main에 살아 있음
  • v0.5.0 release-tagged, maintenance mode 진입. 다음 cycle은 ROADMAP에 정리
화면에 표시된 코드

시리즈 마무리하면서 정리하고 싶은 것

5/18, 5/20 글 보신 분이라면 짧게 가셔도 돼요. 안 보신 분을 위해서 1줄 정리. “Lumen”이라는 LLM 추론 컴파일러 사이드 프로젝트를 6주 전부터 짜고 있어요. ChatGPT 같은 AI 모델이 답을 만들 때 그 계산을 더 빠르게 해주는 코드예요. llama.cpp(ggml)이라는 전 세계 표준이 있는데 처음부터 다시 짜보고 싶었어요. 책 100번 읽는 거랑 한 번 직접 짜보는 거랑 차이가 너무 커서요.

6주 동안 v0.1.0부터 v0.5.0까지 왔어요. 매 release마다 측정 가능한 가속이 있었고, v0.1 4.43 토큰/초에서 v0.5 67 토큰/초까지 약 15배 빨라졌어요. 같은 모델, 같은 정답으로요.

근데 그 6주 안에서 가설을 11번 세웠는데 측정해보니 8번이 부정이었어요. 사실 처음엔 자기 의심이 컸어요. “내가 이 분야 제대로 알고 있나” “직관이 자꾸 틀리는데 이렇게 가도 되나” 같은. 근데 11번 누적하니까 패턴이 보였어요. 측정 없이 직관만으로 가면 11번 중 절반은 잘못된 방향이었을 거예요. 측정 인프라부터 단단히 짜둔 게 제일 잘한 결정이었어요.

이 글에서는 그 11번 사이클을 정리하고, 사이드 프로젝트라는 게 결국 이런 거구나 정리하려고 해요. 작년 이맘때 다른 사이드 프로젝트 만들 때만 해도 이런 패턴 몰랐거든요. 글로 풀면서 다음 사이드 프로젝트(또 시작할 거예요)에서 같은 실수 줄이려는 의도도 있어요.

11번 가설 중에 어떤 게 부정됐나

시간 순으로 정리해요. 자세한 디테일은 시리즈 이전 글들에 다 있어요.

Phase가설 (직관)측정 결과
7.MQ8 정수 dot product가 fp32 매트멀보다 빠를 것net-neutral
7.NVNNI 단일 accumulator도 충분히 빠를 것-3.6%
7.OVNNI 4-acc가 fp32 4-acc보다 빠를 것-2.7%
7.R/S/TAVX-512 ZMM이 YMM의 2배 빠를 것-4.5%
8.Bchunk 크기를 L2 cache fit하면 빨라질 것-3.5%
8.Csoftware prefetch가 메모리 지연 hide할 것8t -49%
8.D.3prefill batching이 5~10배 가속을 줄 것2.9배 회귀
8.D.3 retroattention이 prefill 회귀 원인일 것1%만 (false)

8번 부정 + 1번 거짓 진단. 직관으로는 다 합리적이었어요. 책에도 나와 있는 패턴들이에요. ZMM은 lane width 2배니까 빨라야 하고, 캐시 fit하면 cache miss 줄어드니까 빨라야 하고, prefetch는 메모리 latency hide니까 빨라야 하고, batching은 weight reuse 살리니까 빨라야 해요. 다 부정.

이 중에 가장 자조가 컸던 건 8.D.3이었어요. 1주일 동안 prefill 인프라 짰는데 결과가 -2.9배. 그리고 commit message에 자신 있게 “attention이 원인”이라고 적었는데, 다음 날 50줄 측정으로 1%만이 나오니까 제가 적은 commit message에 제가 비웃음 당한 셈이었어요. 진짜 허탈했어요.

컬러풀한 프로그래밍 코드

진짜 win이었던 것 2~3개

반대로 win은 매우 적었어요. 솔직히 3개로 쳐줘도 되나 싶을 정도.

8.A — ThreadPool 재설계: 기존 ThreadPool은 mutex로 worker가 task 받는 구조였는데, atomic counter로 바꿨어요. 1 스레드에서 +9%, 2 스레드에서 +15%. 8 스레드에서는 +3%만이라 noise 영역. 1t/2t에서만 의미있는 win.

8.D.5 — N>1 커널 진단 확정: 이건 perf win이 아니라 측정 데이터로 진짜 병목 위치를 확정한 거예요. 50줄 단위 벤치마크로 “N>1 매트멀 커널이 N=1 커널×N보다 2.5배 느리다”는 명확한 숫자를 얻었어요. 다음 cycle 진입점이 명확해졌어요.

8.E.1 — N=1 fan-out 회복: 8.D.3 회귀에서 dispatcher 변경만으로 빠져 나왔어요. pp32 22.65 → 54.15 tok/s, 2.39배 회복. 다만 baseline까지는 17% 부족.

이게 v0.5 cycle의 진짜 진척이에요. 코드 양으로 보면 부정 사례가 5배 더 많고, 진척 비율로 보면 1.376 → 1.304. 사이드 프로젝트 6주 동안 이 정도 진척이 정직한 비율이라고 봐요.

제일 의외였던 발견

v0.5 사이클에서 가장 인상 깊었던 건 perf win이 아니라 발견이었어요.

Phase 7.U에서 격차 분석하던 중에, 스레드 수별로 측정하다가 우연히 단일 스레드 비교 row를 찍어 봤어요. 결과 보고 진짜 놀랐어요.

스레드 수Lumenggml누가 빠른가
145.6 tok/s40.4 tok/sLumen +13%
260.862.5ggml +3%
466.586.3ggml +30%
867.487.9ggml +30%

단일 스레드에서 Lumen이 ggml보다 13% 빠른 거예요. ggml은 5년 누적인데 6주 만든 코드가 같은 매트멀 형상에서 더 빠르다는 게 솔직히 안 믿겼어요. 측정 잘못한 건가 다시 해봤는데 같은 결과.

의미가 큰 발견이었어요. 우리 마이크로커널(매트멀 계산 핵심)은 ggml에 안 진다는 거예요. 1.30배 격차가 본질적으로 멀티스레드 scaling 효율 차이라는 결론을 굳혔어요. 그러면 격차 좁히기 위해 마이크로커널을 더 갈고 닦을 필요가 없어요 — scaling 효율을 손대야 해요.

이게 측정 없으면 절대 알 수 없는 거였어요. 막연히 “ggml이 그냥 더 잘 짠 거”라고 받아들이고 마이크로커널 더 튜닝하는 방향으로 갔으면 1주일 더 헛수고했을 거예요. 진짜 막힘과 진짜 진척의 갈림길이었어요.

commit message에 추측 적지 말 것

여기는 짧게 끊을게요. 사실 이 부분은 따로 글 한 편 쓸 가치가 있는데, 한 줄로 줄이면 이거예요.

commit message에 측정 안 한 추측 절대 적지 말 것. 8.D.3에서 “attention이 원인”이라 적은 게 다음 날 8.D.4 측정으로 부정. 만약 다른 사람이 그 commit 읽으면 그 추측을 받아들이고 잘못된 방향으로 갈 수 있어요. 진짜 사이드 프로젝트 한 명만의 코드라도 future me가 다른 사람이에요. 1주일 후의 저는 1주일 전 저를 잘 기억 못해요.

이 한 패턴 강화. 측정 없는 추측은 commit에 적지 않거나 “추측이지만 검증 안 됨”이라고 명시.

모니터 위 코드 라인

왜 인프라를 폐기 안 하나

제가 8번 부정 사례 모두에서 코드를 살려뒀어요. AVX-512 ZMM 인코더 12개, prefetch 인코더 3개, prefill plumbing 함수들, chunk_rows L2 cap 헬퍼 — 다 main 브랜치에 있어요. default-off 상태로요.

이게 처음엔 미신 같이 느꼈는데, 6주 누적하면서 진짜 가치를 알게 됐어요. 이전에 부정된 측정이 미래 다른 조건에서 win이 될 수 있어요.

7.O의 4-accumulator VNNI 인프라가 7.P에서 부활한 게 그 증거예요. 7.O에서는 -2.7% 회귀였는데, 7.P에서 shape-aware dispatcher 추가하면서 짧은 K 매트멀에만 활성화하니 큰 win이 됐어요. 코드 자체는 그대로, 활성화 조건만 변경.

이번 ZMM 인프라도 마찬가지예요. Zen 4에서는 double-pumped 256-bit 구현 때문에 회귀였지만, native 512-bit silicon(Intel Sapphire Rapids, Zen 5+)에서는 측정이 다를 거예요. 그 호스트 만나면 host_supports_avx512() 한 줄만 바꿔서 활성화 가능.

그래서 측정-주도 부정은 “이 코드는 잘못됐다”가 아니라 “이 조건에서는 동작 안 한다”예요. “다른 조건을 기다리자”. 인프라는 살려두고 default-off로 가는 게 그 결론이에요.

사이드 프로젝트의 본질

v0.5 마무리하면서 사이드 프로젝트라는 게 결국 뭔지 정리해 봤어요. 저는 회사에서 정보보안 일을 하고, 퇴근 후 1~2시간 + 주말 30분 정도가 사이드 프로젝트 시간이에요. 진짜 적어요. 그 시간으로 6주 동안 v0.1.0에서 v0.5.0까지 왔는데, 정직히 1주에 commit 5~10개 정도가 한계예요.

이 호흡으로 만들 수 있는 것:

  • 처음 짜는 분야의 직접 경험 — 책으로 못 얻는 거
  • 측정-주도 의사결정 패턴 누적 — 직장 일에도 도움
  • 회고 글 쓰기 습관 — 메타 패턴 발견
  • GitHub 공개 자산 — 포트폴리오
  • 한 분야에 1번 발 디딘 경험 — 다음 사이드에 토대

못 만드는 것:

  • production-ready 도구 — 시간이 절대 부족
  • 커뮤니티 — 외부 PR 받기까지 한참
  • 큰 마일스톤 매주 — 1~2주가 기본 단위
  • 매일 진척 — 어떤 주는 0 commit도 있어요

이걸 받아들이는 게 사이드 프로젝트 지속의 핵심인 것 같아요. 회사 일처럼 매주 큰 진척 기대하면 호흡이 무거워져요. “이번 주는 측정 1번만 해도 진척”이라고 생각하면 가벼워요. 진짜로 호흡 무거워지면 잠시 쉬어도 코드는 그대로 있어요.

여담인데, 작년에도 비슷한 호흡으로 다른 사이드 프로젝트 했어요. 그건 9개월 갔는데 결국 마무리 못하고 흐지부지 됐어요. Lumen은 v0.5.0 release tag 박고 정리하는 거니까 더 좋게 끝났다고 생각해요. 사이드는 끝낼 줄 아는 것도 능력이에요.

대신 질문 해드릴게요

이제 안 짤 거예요?

“안 짤 거”가 아니라 “잠시 쉬는 거”예요. v0.6.0에 진입할 마일스톤은 정해져 있어요(ROADMAP.md에 적어둠). 다만 호흡이 좋아지면 다시 시작할 거고, 안 좋아지면 한 달 더 쉴 수도 있어요. 사이드라서 스케줄 강제 안 해요.

11번 부정당하면서 안 지치셨어요?

솔직히 5회 즈음에는 지쳤어요. “내가 이거 진짜 모르는 건가” 자기 의심 컸어요. 근데 측정 데이터가 누적되니까 패턴이 보였어요. 직관은 자주 틀리지만 측정은 진실을 알려주거든요. 지친다기보다 “예상했던 결과”가 됐어요. 11번 사이클 후에는 가설 세우면서 “어차피 절반은 부정될 거다” 미리 가정. 마음이 가벼워졌어요.

회사 일이랑 사이드 프로젝트 시간 어떻게 나눠요?

회사 일은 회사 시간에만 해요. 절대 사이드로 안 가져옵니다. 정보보안 업무라 더 그래요. 회사 코드는 외부 노출 우려가 있어서 노트북에 다운로드도 안 해요. 사이드는 완전히 별개 영역. 머리 식히는 거예요. 회사 일에서 막혔던 디자인 패턴 사이드에서 한 번 짜보면 다시 회사 일에 적용되기도 해요. 양방향이에요.

도와주는 도구는 뭐 써요?

Claude Code예요. 개인 사이드 프로젝트라 자유롭게 같이 작업해요. Rust 코드 짜기 + 측정 분석 + 회고 글 쓰기. 회사 일은 절대 안 들고 가요(외부 노출 우려). 그리고 도구는 어디까지나 도구. 측정 인프라 짜고 가설 세우고 측정하고 결론 내리는 건 다 본인이 하는 거예요. 도구가 짠 코드도 매번 직접 읽어요. 결국 결과가 정답인지 측정으로 확인해야 하니까요.

사이드 프로젝트 시작하시는 분께 조언 1개?

측정 인프라부터 짜세요. 첫 commit이 “Hello World”여도 두 번째 commit은 “Hello World 시간 측정”이면 좋아요. 측정 없이 가는 사이드는 6주 후에 자기가 뭘 했는지 잊어요. 그리고 1주에 commit 0개여도 괜찮아요. 매주 진척 기대하면 호흡 무거워져요. 사이드는 길게 가는 거예요.

다음 사이드 프로젝트 뭐 할 거예요?

아직 모르겠어요. Lumen이 컴파일러 + Rust였으니까, 다음은 다른 분야가 좋겠어요. 임베디드 펌웨어? 분산 시스템? 모르겠어요. 호흡이 다시 좋아지면 그 때 결정. 지금은 잠시 휴식.

레추의 총평

6주 동안 사이드 프로젝트로 LLM 추론 컴파일러를 처음부터 짜봤어요. 결과:

  • v0.1.0 → v0.5.0 (15배 가속)
  • ggml 대비 8 스레드 1.30배 격차, 단일 스레드 +13% 우위
  • 측정-주도 사이클 11회 (win 2 + 부정 8 + 진단 1)
  • 회고 블로그 16편 + 마무리 1편
  • v0.5.0 GitHub release tag

사이드 프로젝트 한 사이클의 정직한 결과예요. 자랑할 만한 큰 진척은 아니지만 honest engineering 자산이 누적됐어요. 측정 데이터 + 회고 글 + 부정 사례 + default-off 인프라. 다음 사이클 시작하는 사람(또는 future me)이 똑같은 함정 안 빠지게 도와줄 자산이에요.

실천 체크리스트로 정리할게요. 사이드 프로젝트 진행하시는 분들께:

  • 측정 인프라부터 단단히 짜기 — step별 시간 측정 가능해야 가설 부정 가능
  • commit message에 측정 안 한 추측 절대 적지 말기 — future me가 다른 사람
  • 가설 부정 후에도 인프라 살리기 — 다른 호스트/조건에서 살아날 수 있음
  • 1주에 commit 0개도 OK — 매주 진척 강제하면 호흡 무거워짐
  • 회고 블로그 한 편씩 쓰기 — 메타 패턴 발견에 진짜 도움
  • 잘 끝낼 줄 알기 — release tag 박고 잠시 쉬는 것도 능력

코드: github.com/redchupa/lumen. v0.5.0 GitHub release page에서 측정 데이터 + 회고 시리즈 인덱스 + Roadmap 다 확인 가능해요. 시리즈 마무리 글이라 댓글로 다음 사이드 프로젝트 아이디어 추천 받습니다. 새로 시작할 때 참고할게요.


이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

레드추파가 직접 써보고 고른 상품만 모았어요

레추 추천 상품 모아보기


쿠팡에서 구경하기

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤