diff --git a/docs/release-notes/v0.22.0-draft.md b/docs/release-notes/v0.22.0-draft.md index 2660e66..8c2d1fe 100644 --- a/docs/release-notes/v0.22.0-draft.md +++ b/docs/release-notes/v0.22.0-draft.md @@ -65,10 +65,33 @@ double-free 경로를 원천 차단한다. NUMA 노드 바인딩이 더 필요 - 문서: README Configuration, `docs/SMOKE.md` config 예시, `docs/ARCHITECTURE.md` crate 그래프/트리에 candle provider 반영. -## 잔여 검증 (사용자 실행) +## 검증 / 도그푸딩 -듀얼소켓 NUMA 서버에서 `provider=candle` 로 5150-doc ingest 가 double-free -없이 EXIT=0 완주하는지가 본 release 의 최종 인수 게이트다 (meta-spec §4.3). -패리티(candle vs onnxruntime): cosine_min = 1.000000, 차원별 max 절대오차 = -2.01e-7 — 벡터가 사실상 동일하므로 `embedding_version` 유지(재색인 0). 재현은 -`crates/kebab-embed-candle/tests/parity.rs` (`--ignored`). +- **패리티 (candle vs onnxruntime)**: 동일 e5-large 가중치로 cosine_min = + 1.000000, 차원별 max 절대오차 = **2.01e-7**. 벡터가 사실상 동일 → + `embedding_version` 유지(재색인 0). 재현: `crates/kebab-embed-candle/tests/parity.rs` + (`--ignored`). +- **전체 도그푸딩 (2026-06-02)**: `provider=candle` 로 도그푸딩 코퍼스 전체 + 재색인 — **997 docs / 23,151 chunks, 에러 0** 완주 (≈9.5 h, 단일소켓 VM). + candle 가 23k+ 청크를 메모리 오류 없이 처리함을 확인. +- **A1(taskset/numactl) 반증**: NUMA 서버에서 `taskset -c 0-3` 으로 스레드를 + 4개로 묶어도 onnxruntime 은 그대로 죽었다(6/5150 segfault). 스레드 축소는 + 해법이 아니며, **`provider=candle` 만이 실 해법**이다 (candle 은 onnxruntime 을 + 호출하지 않음). +- **최종 인수 게이트 (사용자)**: 그 듀얼소켓 NUMA 서버에서 `provider=candle` 로 + ingest 가 EXIT=0 완주 — 배포·실사용이 이 검증을 겸한다. + +## 성능 노트 (중요) + +candle CPU 임베딩은 onnxruntime 대비 약 **3~4× 느리다** (e5-large/512-tok 의 +순수-Rust 커널 비용). 측정상 ~1.86 s/chunk, CPU 약 4코어 활용. **이는 의도된 +트레이드오프** — onnxruntime 이 전 코어를 AVX-512 로 빡빡하게 굴리는 바로 그 +경로가 NUMA 에서 힙을 손상시켜 죽기 때문이다. "느려도 완주" > "빨라도 크래시". + +- Intel **MKL 가속을 실험했으나 부정 결과**: MKL 은 코어를 더 쓰지만(8~9코어) + 오히려 38~50% 느렸다(과다구독 + MKL 2020.1 오버헤드). 채택하지 않음. +- 더 많은 코어/스레드로는 빨라지지 않는다(병목이 코어 수가 아님). 속도가 + critical 하면 청크 길이 단축 / 더 작은 모델 / GPU 가 레버다(별도 검토). +- 9.5 h 는 **최초 전체 색인 1회 비용**이며, 이후 증분 ingest 는 새/변경 문서만 + 처리해 저렴하다. 단일 워크스테이션(비-NUMA)에서는 기본 `fastembed` 가 더 빠르니 + candle 은 NUMA 호스트 전용 opt-in 으로 둔다. diff --git a/tasks/HOTFIXES.md b/tasks/HOTFIXES.md index 35ab88d..b6bdfac 100644 --- a/tasks/HOTFIXES.md +++ b/tasks/HOTFIXES.md @@ -58,8 +58,33 @@ CI 기본 제외). 이 수치가 `embedding_version` 유지(재색인 0) 결정 `num_threads` 가 serde default(0)로 채워져 그대로 파싱. **잔여 게이트 (사용자 실행, Claude 불가).** 그 듀얼소켓 NUMA 서버에서 -`provider=candle` 로 5150-doc ingest 가 double-free 없이 EXIT=0 완주하는지 -PR 머지 전/후 검증 예약 (meta-spec §4.3). +`provider=candle` 로 ingest 가 double-free 없이 EXIT=0 완주하는지 — 사용자 +배포·실사용이 곧 이 검증을 겸한다 (meta-spec §4.3). + +**도그푸딩 (2026-06-02, 단일소켓 12-thread VM).** `provider=candle` + +`config-candle.toml`(expansion off — 임베더 격리) 로 `/build/dogfood/corpus` +전체 재색인: **scanned=998, new=997, errors=0, stderr=0, KB 997 docs / +23,151 chunks**, duration ≈ 34,329 s (9.5 h). candle 가 23k+ 청크를 메모리 +오류 0 으로 완주 — onnxruntime 이 서버에서 6/5150 에 죽던 것과 정반대. +(이 VM 은 비-NUMA 라 NUMA 자체 재현은 아니나, candle 은 onnxruntime 을 +호출하지 않으므로 동일 크래시 종류가 구조적으로 불가.) + +**A1(taskset/numactl) 워크어라운드 실서버 반증 (2026-06-02).** 사용자가 NUMA +서버에서 `taskset -c 0-3 kebab ingest`(fastembed/onnx 바이너리) 실행 → 4코어로 +제한했는데도 6/5150 에서 `세그멘테이션 오류 (core dumped)`. 스레드 축소가 +onnxruntime 힙 손상을 제거하지 못함(크래시 위치만 3→6 이동). 결론: 이 크래시는 +스레드 *수* 문제가 아니라 onnxruntime 네이티브 코드의 메모리 안전 결함 → +**A1 은 신뢰 불가 우회책. candle(onnxruntime-free)이 유일한 실 해법.** + +**MKL 가속 부정 결과 (2026-06-02).** "candle 이 코어를 더 쓰게" 하려고 candle +`mkl` feature(Intel MKL) 를 벤치 (e5-large, 512-tok 청크, N=32): +pure-Rust 1857 ms/chunk(381% CPU) vs MKL 2574 ms/chunk(896% CPU, rayon12+mkl12) +/ 2792 ms/chunk(817% CPU, rayon1+mkl12). **MKL 은 코어를 더 쓰지만 모든 설정에서 +38~50% 더 느림** (MKL 2020.1 sgemm + 스레드 오버헤드/과다구독; candle 0.10.2 는 +f16 `hgemm_` 미해결로 링크도 실패 — 벤치는 호출 안 되는 스텁으로 우회). 또 +pure-Rust 는 rayon 8↔12 간 throughput 불변(~1.86 s/chunk) — 병목은 코어 수가 +아니라 candle e5-large/512tok 커널 효율. **결론: MKL 미채택, 순수-Rust 유지(안전 +최상 + CPU 에서 더 빠름). 속도 레버는 코어가 아니라 청크 길이/모델 크기/GPU.** amends: `docs/superpowers/specs/2026-06-01-embed-candle-track-spec.md`.