English · Español
Break 00 — Servir sin batching, ver el throughput colapsar¶
🇪🇸 La forma más rápida de sentir el valor del batching es quitarlo. Este
/breakdesactiva elBatchingSchedulery deja que cada petición use una matmul propia. Bajo C=1 todo va bien; bajo C=8 la cola crece sin freno y la p95 se dispara.
Qué vas a hacer¶
Desactivar la capa de batching en el servidor de inferencia para que cada petición ejecute su propio forward pass, end-to-end serializado en el hilo BLAS de NumPy. Conducir el servidor con el generador de carga del lab 02 y observar el throughput colapsar.
Paso 1 — Localiza el scheduler¶
src/miniserve/scheduler.py # the BatchingScheduler class (Phase 33 lab 02)
src/miniserve/handlers.py # the /correct handler that submits to it
Paso 2 — Introduce el bug (≤ 5 líneas)¶
En src/miniserve/handlers.py, cambia la ruta de envío para que el handler salte el scheduler y llame a model.forward() directamente:
# OLD
result = await scheduler.submit(request_id, prompt_ids)
# NEW (the broken version)
result = model.forward(prompt_ids) # synchronous, no batch coalescing
Es el diff más pequeño posible. No cambian imports. El servidor sigue arrancando. El endpoint sigue respondiendo.
Paso 3 — Registra el break¶
learners/borja/phase-33/notes/breaks.md:
- bug-id: 33-01
concept: continuous batching
symptom: p50 doubles at C=2, quadruples at C=4, server queue OOMs at C=16.
hidden_cause: handlers.py bypasses scheduler.submit(); each request serializes
on the NumPy BLAS thread, no batch coalescing happens.
hint_1: "Plot p50 vs concurrency. What shape do you see? Linear? Sublinear?"
hint_2: "Add a log line in BatchingScheduler.submit(). Does it print under load?"
hint_3: "grep for 'model.forward' in src/miniserve/. Should that call appear there?"
fix_diff: revert handlers.py — submit to scheduler instead of calling forward directly.
Paso 4 — Verifica que es observable¶
Ejecuta loadgen.py del lab 02 con --concurrency 8 --duration 60s. Output esperado:
p50: 1180 ms (target: ≤ 250 ms)
p95: 3400 ms (target: ≤ 600 ms)
rps: 6.2 (target: ≥ 30 rps)
errors: 12% timeout
Los tests del lab 02 en tests/phase33/test_throughput.py se pondrán en rojo.
Paso 5 — El momento de enseñanza¶
La métrica a mirar fijamente es p50 vs concurrencia. Con batching, la curva es aproximadamente logarítmica — la matmul de BLAS amortiza el trabajo entre peticiones. Sin batching, es lineal — cada petición se serializa en la CPU. Borja debería poder derivar cuál de las dos está en el código a partir de la forma de la curva antes de leer handlers.py.
Cuando esté atascado, la cascada de pistas camina desde "mira los datos" → "mira los logs del scheduler" → "mira el call site". El fix es un revert de una línea; la lección es que "scheduler" en tu diagrama de arquitectura no hace nada salvo que los handlers enruten a través de él.
Reglas duras respetadas¶
- Un solo bug.
- Reversible en 1 línea.
- Observable desde el test de carga (assertion fallando + gráfico visiblemente malo).
- Sin implicaciones de seguridad.
- Los tests no se modifican.
Siguiente: lee ../theory/02-static-vs-continuous-batching.md una vez que el test esté verde de nuevo.