Llama.cpp rendimiento: la aritmética del ancho de banda

En pocas palabras: Un Llama 27B en IQ4_XS corriendo a 5,6 tok/s en un Mac Mini M4 demuestra que la capacidad de RAM no garantiza usabilidad. El ancho de banda es el cuello de botella real; hacé la aritmética antes de invertir.

Un modelo de lenguaje puede cargar perfectamente en la RAM y seguir siendo inútil para trabajo interactivo si el ancho de banda de memoria es el cuello de botella. Tal como se documenta en un análisis técnico, un Llama de 27B cuantizado a IQ4_XS (15 GB) en un Mac Mini M4 generó apenas 5.6 tokens por segundo, muy lejos del techo teórico de 8 tok/s dictado por los 120 GB/s de bus, lo que demuestra que la aritmética de throughput debe preceder a cualquier decisión de hardware o configuración en llama.cpp rendimiento. Cubrimos ese tema en detalle en configurar un LLM local con Ollama.

En 30 segundos

  • Capacidad no es velocidad: Que el modelo ocupe 15 GB en una máquina con 24 GB no garantiza usabilidad; el límite real es cuántos bytes se mueven por segundo.
  • Fórmula de supervivencia: Techo de tokens ≈ Ancho de Banda ÷ Tamaño del modelo. Si tu medición es más del 50% de este techo, estás limitado físicamente por el bus de memoria.
  • Cuantización engañosa: Bajar de IQ4_XS a Q3_K_M solo mejora un 9% la velocidad pero degrada la calidad desproporcionadamente cuando ya eres bandwidth-bound.
  • Diagnóstico rápido: Medí siempre “en caliente” (warm) con el modelo residente para excluir presión de swap; si el ratio es alto, cambiar de GPU o CPU no sirve, necesitás más ancho de banda.

Llama es una herramienta de desarrollo que permite verificar si un recurso encaja en la memoria disponible antes de realizar operaciones de red. Se utiliza para calcular el ancho de banda necesario y evitar fallos por falta de recursos durante la carga de datos.

llama.cpp es un motor de inferencia de código abierto que permite ejecutar modelos de lenguaje grandes (LLMs) localmente optimizando el uso de recursos, mientras que el concepto de “bandwidth arithmetic” es el cálculo crítico que determina si esa ejecución será práctica o frustrante según las especificaciones físicas de tu hardware.

¿Por qué ‘cabe en memoria’ no significa que sea usable?

Ponele que tenés un Mac Mini M4 con 24GB de memoria unificada y ~120GB/s de ancho de banda. Cargás un modelo de 27B parámetros, cuantizado a IQ4_XS, que ocupa 15GB en disco. El sistema operativo dice que todo está bien: el working set recomendado es de 17.76GB, el modelo entra sin hacer swap, reporta 100% de residencia en GPU. Por cada criterio tradicional de “¿cabe?”, esto es un éxito rotundo. Y sin embargo, genera 5.6 tokens por segundo. Eso no es un trabajador interactivo útil. Es apenas un trabajador batch mediocre. Nada en la verificación de capacidad advirtió sobre esta lentitud porque la capacidad mide bytes totales disponibles, mientras que el throughput mide bytes movidos por segundo a través de un bus. Son recursos distintos gobernados por leyes físicas diferentes. Si alguna vez configuraste un servidor y viste que el disco tiene espacio libre pero la base de datos va lenta, sabés de qué hablo: el cuello de botella no estaba en dónde guardabas los datos, sino en cómo llegaban al procesador. El error común es asumir que pasar el “gate de carga” implica pasar el “gate de utilidad”. La carga es gratis de verificar (el archivo existe o no), pero el throughput requiere una medición activa o un cálculo previo. Sin ese paso intermedio, tomás decisiones de compra o configuración basadas en una premisa incompleta.

¿Cómo calcular el máximo de tokens por segundo posible?

llama.cpp rendimiento diagrama explicativo
La generación autoregresiva lee todos los pesos del modelo una sola vez por token generado. No hay magia ni atajos actuales en arquitecturas densas estándar: para producir el siguiente carácter, la GPU o CPU necesita traer desde la memoria toda la información ponderada del modelo. Esto nos deja con una fórmula brutalmente simple para estimar el techo físico de tu rendimiento en llama.cpp: Techo de tokens/segundo ≈ Ancho de Banda de Memoria (GB/s) ÷ Bytes tocados por operación (GB) Volviendo al ejemplo del Mac Mini M4: 120 GB/s ÷ 15 GB = 8 tokens/segundo teóricos. Mediste 5.6. La relación entre lo medido y el techo es 0.70. Ese número es el veredicto total. Cuando tu throughput medido es una gran fracción del techo aritmético, sabés algo concreto: el problema no es tu configuración de software, no es la presión de memoria, no es el throttling térmico. Es simplemente la velocidad a la que se mueven los bytes. Esta regla de dedo cambia todo: si el ratio es ≥ 0.5, estás limitado por ancho de banda y las soluciones de reducción de tamaño están muertas. ¿Alguien verificó esto de forma independiente? El autor del análisis técnico validó estos números en hardware real, demostrando que la teoría coincide con la práctica dentro de un margen razonable de eficiencia (el ancho de banda efectivo suele ser 60-80% del teórico).

¿Cuándo la cuantización agresiva deja de ser útil?

Aquí viene la trampa donde cae casi todo el mundo. Si el modelo va lento, el instinto es “cuantizar más bajo”. Bajamos de IQ4_XS (15GB) a Q3_K_M (13.8GB). Suena lógico: menos bytes, más rápido. Hagamos la división otra vez: 120 GB/s ÷ 13.8 GB = 8.7 tokens/segundo. Pasamos de un techo de 8 a uno de 8.7. Una mejora del 9%. Para lograr ese mísero incremento, sacrificás una cantidad significativa de precisión matemática, porque el error de cuantización no escala linealmente con el tamaño como sí lo hace el ancho de banda. En este régimen, pagás mucho más de lo que ganás. Subís el modelo, lo probás en local, funciona bárbaro, lo mandás a producción y de repente todo se rompe porque nadie hizo la cuenta antes, asumiendo que menos peso significaba proporcionalmente más velocidad sin entender que el cuello de botella era el bus, no la capacidad de almacenamiento. El autor menciona que descartó ese plan sin siquiera descargar el modelo, gracias a la aritmética previa. Esa es la verdadera optimización: evitar tardes enteras haciendo benchmarks de configuraciones que físicamente no podían ganar.

¿Qué intervenciones funcionan si el cuello de botella es la memoria?

Una vez que nombrás correctamente el recurso restringido (ancho de banda), el conjunto de intervenciones posibles se reduce drásticamente. Tunear parámetros de `llama.cpp` como `n_threads` o `batch_size` no va a mover la aguja si el bus ya está saturado. Lo que sí funciona son cambios estructurales:
IntervenciónEfecto en ThroughputCosto/EsfuerzoViabilidad
Aceptar latencia altaNinguno (mantiene 5.6 tok/s)BajoSolo para tareas batch/no interactivas
Cambiar hardware (más bus)Directo (ej. 273GB/s → ~18 tok/s)AltoÚnica solución real para tiempo real
Mover carga a servidorDepende del servidorMedioSi tenés acceso a GPUs de datacenter
Reducir cuantizaciónMínimo (<10%)BajoIneficiente, pierde calidad sin ganar velocidad
El veredicto cambia con el hardware, no con el tamaño del modelo. Decir “este modelo es demasiado lento” es falso. Lo correcto es decir “este modelo es demasiado lento en este hardware específico“. En una máquina con 273 GB/s de ancho de banda, ese mismo modelo de 15GB supera los 18 tok/s, volviéndose totalmente viable para chat en vivo. Si estás evaluando infraestructura para correr cargas similares en la nube, asegurate de mirar las especificaciones de memoria de las instancias, no solo los vCPUs. Para inferencia de LLMs a menudo vas a necesitar buscar instancias especializadas con buses de memoria muy anchos o GPUs de gama alta.

¿Cómo diagnosticar si tu sistema está limitado por swap o por ancho de banda?

Mucha gente confunde los síntomas. Ven lentitud y piensan “debe estar usando swap” o “falta RAM”. Pero medir en frío, con otras aplicaciones abiertas, contamina el dato. Tenés que medir “en caliente”, con el modelo ya residente en memoria y el sistema estable. Si después de limpiar procesos pesados y asegurar que no hay spillover, el rendimiento sigue clavado cerca del techo calculado (ratio > 0.5), entonces es ancho de banda. Punto. No hay configuración de software que arregle la física del bus de memoria. Los anti-patrones más comunes que vi en foros y chats técnicos:
  • “Cargó, así que podemos usarlo”: Falso. Cargar es el gate de capacidad. Pasar ese gate deja el throughput totalmente desconocido.
  • “Es lento, así que cuantizo más bajo”: En regímenes limitados por ancho de banda, esto es inútil. Solo degradás la calidad.
  • “Debe ser presión de memoria”: Si no medís en caliente, mezclás el techo físico con congestión transitoria. Acá no había presión, el techo era exactamente donde la aritmética lo ponía.
La única forma de refutar esta conclusión sería encontrar una arquitectura que deje de leer todos los pesos por token, como modelos MoE (Mixture of Experts) con sparsity muy agresiva o decodificación especulativa avanzada, pero eso rompe la suposición básica de “bytes tocados = tamaño del modelo” y obliga a rehacer la división con cifras reales distintas.

Errores comunes al optimizar LLMs locales

1. Ignorar la diferencia entre VRAM y Bandwidth: Mucha gente cree que tener 24GB de VRAM es suficiente para correr cualquier cosa rápida. Si el bus es de 100GB/s y el modelo es grande, vas a esperar. 2. Benchmarking en frío: Correr la primera pregunta después de iniciar el servicio incluye tiempos de carga y inicialización de kernels. Siempre descartá los primeros 10-20 tokens para medir el steady-state. 3. Asumir que “menos es mejor”: Cuantizar a Q2 o Q1 parece inteligente para ahorrar espacio, pero si no sos memory-constrained, solo estás tirando calidad a la basura por ganancias marginales de velocidad. 4. No escribir el falsificador: Antes de comprar hardware nuevo, escribí qué número de ancho de banda cambiaría tu veredicto. Si no lo tenés claro, vas a gastar plata en la dirección equivocada.

Preguntas Frecuentes

¿Por qué un modelo LLM va lento aunque entre en la RAM?

Porque la RAM mide cuánto espacio tenés, no qué tan rápido podés acceder a él. Los modelos autoregresivos necesitan leer todos sus pesos para generar cada token, convirtiendo el ancho de banda de memoria (GB/s) en el cuello de botella principal, independientemente de la capacidad total disponible.

¿Cómo calcular el máximo de tokens por segundo posible?

Dividí el ancho de banda de memoria de tu hardware (en GB/s) por el tamaño del modelo cargado en memoria (en GB). Por ejemplo, 120 GB/s dividido 15 GB da un techo teórico de 8 tokens por segundo. Tu rendimiento real será menor, típicamente entre el 60% y 80% de ese valor.

¿La cuantización mejora la velocidad o solo el espacio?

Mejora ambos, pero de forma desproporcionada. Reducir el tamaño baja los bytes a leer, aumentando el techo de tokens por segundo linealmente. Sin embargo, si ya estás limitado por ancho de banda, la ganancia de velocidad es mínima comparada con la pérdida de calidad del modelo, haciendo que muchas veces no valga la pena.

¿Qué hardware necesito para acelerar la inferencia local?

Necesitás mayor ancho de banda de memoria, no necesariamente más RAM. Placas de video con buses HBM (High Bandwidth Memory) o CPUs con múltiples canales DDR5 de alta frecuencia son clave. Cambiar de un chip con 120 GB/s a uno con 273 GB/s duplica o triplica la velocidad de generación para el mismo modelo.

Conclusión

Hacer la aritmética del ancho de banda antes de tocar el teclado o sacar la tarjeta de crédito es la habilidad más subestimada en la ingeniería de LLMs locales hoy en día. “Cabe” y “funciona rápido” son dos puertas distintas, y la primera es gratis de abrir, lo cual explica por qué tantos desarrolladores entran por ella creyendo que terminaron el trabajo. Para equipos en Latinoamérica que buscan montar servicios de IA on-premise, esto significa priorizar la inversión en buses de memoria rápidos (como A100/H100 o Apple Silicon Pro/Max) por encima de simples cantidades masivas de RAM barata. Si tu objetivo es chat en tiempo real, un modelo pequeño en hardware rápido gana siempre contra un modelo grande en hardware lento. Y si no podés cambiar el hardware, aceptá la realidad batch: dejá que trabaje de noche y no intentes interactuar con él en vivo.

Fuentes

Desplazarse hacia arriba