# M2 — MLX gemma-4 동시 처리 Capacity Bench

**측정일**: 2026-05-02
**대상**: Mac mini MLX :8801 `gemma-4-26b-a4b-it-8bit` (Tailscale 100.76.254.116)
**범위**: read-only `/v1/chat/completions` 호출만. 4.0 가드 준수 (compose / migration / queue / worker restart / source_channel insert / SearXNG 도입 모두 0건). config.yaml / Ollama 모델 변경 없음.
**bench 스크립트**: `/tmp/bench_M2_mlx.py` (격리, main pipeline 미연결)
**plan 참조**: `~/.claude/plans/users-hyungiahn-library-cloudstorage-sy-binary-dongarra.md` §4.

---

## 1. 사전 점검

| 항목 | 상태 |
|---|---|
| MLX `/v1/models` healthcheck | OK (`gemma-4-26b-a4b-it-8bit` 단일 모델) |
| 진행 중 background queue (사전) | classify 1건 processing, classify 10건 pending, deep_summary 4건 pending — **MLX 자원 사용 중** |
| eval runner / `/api/search/ask` 동시 진행 | 별도 호출 없음 (Document Server 자체 ask 트래픽은 배치 외 시점) |
| 시간대 | 평일 오후 (한국시간) — peak 외 |

배경 queue 가 MLX 동시 사용 중인 상태에서 측정 진행 — **운영 환경 reflective benchmark** 로 의미 있음.

---

## 2. 시나리오

| 항목 | 값 |
|---|---|
| 입력 본문 | ~500 토큰, 한·영 mixed (ASME B16.5 / KGS Code / 가스기사 도메인 sample) |
| 프롬프트 작업 | "한국어 200자 이내 요약, technical key points only" |
| `max_tokens` | 200 (stop 보장) |
| `temperature` | 0 |
| 입력 prompt_tokens | ~500 (실측 19 tokens 단순 프롬프트와 별도. 실제 PROMPT 본문 포함 길이) |

각 응답은 모두 `finish_reason='stop'`, `completion_tokens=120` 으로 일관 — **출력 토큰 수가 일정**해 latency 비교가 깨끗함.

---

## 3. N=1 baseline (5 serial)

```
call 1: ok=True elapsed=3.67s ctok=120
call 2: ok=True elapsed=3.41s ctok=120
call 3: ok=True elapsed=3.42s ctok=120
call 4: ok=True elapsed=3.60s ctok=120
call 5: ok=True elapsed=3.47s ctok=120
```

| metric | value |
|---|---|
| n | 5 |
| min | 3.41s |
| max | 3.67s |
| avg | **3.51s** |
| p50 | 3.47s |
| p95 | 3.67s |
| error_count | 0 |
| error_rate | 0% |
| completion_tokens_avg | 120 |

**관찰**: 매우 안정 (편차 0.26초). 메모리 `project_search_v2.md` 의 "gemma-4 ~10.5초" (Phase 2 측정) 와 차이는 본 시나리오가 짧은 출력 (120 tok vs Phase 2 의 더 긴 출력) + 검색 query 성격 차이 때문.

---

## 4. N=2 parallel (6 calls, 3 batches via thread pool)

```
call 4: ok=True elapsed=14.38s ctok=120
call 5: ok=True elapsed=14.37s ctok=120
call 6: ok=True elapsed=17.12s ctok=120
... (call 1~3 도 모두 ok)
```

| metric | value |
|---|---|
| n | 6 |
| min | 6.74s |
| max | 35.01s |
| avg | **19.88s** |
| p50 | 15.75s |
| p95 | **35.01s** |
| error_count | 0 |
| error_rate | **0%** |
| completion_tokens_avg | 120 |

**해석**:
- **error 0** — concurrency 2 client 호출에 대해 MLX 안정.
- **latency 큰 폭 증가** — N=1 대비 p95 9.54×, p50 4.54×, avg 5.66×.
- 원인: MLX server (`mlx_vlm server`) 가 단일 프로세스 + GPU 1 → 본질적으로 **concurrency=1 직렬 처리**. N=2 client 호출은 MLX 내부 큐에서 직렬화. 추가로 background classify 1건 processing 중이라 경합.
- 6 calls × ~3.5초 = ~21초 총 직렬 처리 시간. max 35초는 background queue 점유 + 큐잉.
- 이는 메모리 `feedback_analyzer_async_only.md` ("semaphore concurrency=1 필수") 와 일치하는 **이미 알려진 특성**. 새로운 위험 신호 아님.

---

## 5. plan 4.0 중단 조건 점검

| 조건 | 측정 | 판정 |
|---|---|---|
| `error_rate > 0` | 0% | 미발생 |
| **p95 latency N=1 대비 3배 이상 증가** | **9.54×** | **트리거** |
| MLX healthcheck 실패 | OK | 미발생 |
| `/api/search/ask` 또는 eval 시간대 겹침 | 사전 점검 시 ask/eval 없음 | 미발생 |

**결론**: p95 3× 트리거 발생 → **N=4 자동 진행 금지**. plan 명시 (`N=4 는 N=2 에서 error_rate=0 AND p95 acceptable 일 때만`). N=4 는 별도 사용자 승인 후 수행.

다만 latency 9.5× 증가는 MLX concurrency=1 본질적 특성이지, 새로운 운영 위험은 아님. 이미 운영 중인 ask / classify 트래픽이 동시에 들어오면 동일하게 늘어남.

---

## 6. plan 4.1 게이트 판정 (M2 관련)

### 게이트 2 — Gemma 요약 30건/일 ≤ 10분 (concurrency 1)

| 항목 | 값 |
|---|---|
| 단위 시간 (avg) | 3.51s |
| 30건 직렬 처리 시간 | 30 × 3.51s = **105.4s = 1.76분** |
| 임계값 | ≤ 10분 |
| **판정** | **✓ PASS** (여유 5.7×) |

### 게이트 3 — concurrency 2 error_rate 0 = 여유 있음

| 항목 | 값 |
|---|---|
| N=2 error_rate | 0% |
| 임계값 | error_rate = 0 |
| **판정** | **✓ PASS** |

### 게이트 3 보강 — latency 영향 (참고용)
- N=2 동시성 시 평균 19.88초, p95 35초 — LocalResearch 본격 가동 시 **운영 ask 트래픽과 동일 시간대 web 요약이 겹치면 응답 약 5~10× 지연** 가능.
- 완화책 (Phase 1 본격 plan 단계 결정): (a) web 요약은 background queue + concurrency 1 직렬 (실시간 아님) (b) ask 와 시간대 분리 (야간 배치)

---

## 7. M2 단계 요약

- **N=1 baseline**: avg 3.51s, p95 3.67s, error 0 → 매우 안정
- **N=2 parallel**: avg 19.88s, p95 35.01s, error 0 → MLX 직렬 처리로 latency 9.5× 증가, 단 안정성/완성도는 유지
- **N=4 미실시**: plan 4.0 중단 조건 트리거 (p95 3× 초과). 사용자 승인 후 별도 수행.
- **plan 게이트 2 + 3 모두 PASS**

## 8. 다음 단계
M3 (bge-m3 batch 1/8/32 임베딩 벤치) — 운영 embed worker 시간대 분리 후 진행.
