El Neural Engine del M3 tenía un cuello de botella escondido y lo encontraron con un FFT

El Neural Engine del M3 tenía un cuello de botella escondido y lo encontraron con un FFT

El Neural Engine del M3 tenía un cuello de botella escondido y lo encontraron con un FFT

Hay historias de ingeniería que me encantan porque empiezan con alguien aburrido mirando números y terminan cambiando lo que sabemos de un chip que millones de personas usan a diario. Esta es una de esas. Eileen Yoon se puso a medir cuánto ancho de banda DRAM estaba usando el Neural Engine (ANE) del Apple M3 durante el decode de un solo token, y se topó con algo raro: según la dimensión del tensor, el throughput se caía de 44,5 GB/s a 16,93 GB/s. Sin error, sin crash, solo el chip funcionando a un tercio de su velocidad y nadie enterándose.

Qué estaba pasando realmente

Después de 2.747 observaciones (67 dimensiones distintas por 41 rondas aleatorizadas en un M3 Air), el patrón quedó clarísimo: cada vez que el tamaño total de los pesos del modelo era un múltiplo entero de 1 MiB, el controlador DMA del kernel entraba en un régimen de throttling y el throughput colapsaba a 17-19 GB/s, cuando lo nominal es 45-60 GB/s. Sí, leyeron bien: el problema era que el modelo era demasiado redondo en bytes. Hizo hasta un FFT del throughput contra la dimensión del tensor y encontró una resonancia con armónico dominante en 2048. Nadie debería tener que hacer un análisis de Fourier para debuggear una GPU, pero acá estamos.

La conclusión final es elegante: el controlador tiene una ventana de prefetch especulativo que se comporta mal exactamente en los límites de página de 16 KiB de Apple Silicon. El bug es de rendimiento (un erratum RTL), no de corrección: los datos llegan bien, solo que llegan lentos. De los modelos que corría, 7 de 15 estaban afectados sin que nadie lo supiera.

El fix es de software y duplica el rendimiento

Lo mejor de todo: el workaround es evitar la ruta problemática partiendo las transferencias para que nunca caigan en un múltiplo exacto de 1 MiB. Con eso, Llama 3.2 1B pasó de 10,0 a 24,3 tokens/s (el uso de DRAM subió de 24,7 a 60 GB/s) y Qwen3-8B de 1,36 a 2,97 tokens/s. Literalmente más del doble de rendimiento en inferencia local, gratis, sin tocar el hardware. Solo alguien tuvo que sentarse a medir con rigurosidad, descartar hipótesis una por una (contención entre los 16 cores, correlación espacial de direcciones en DRAM, drift térmico) y no conformarse con «a veces va lento, será el macOS».

Lo que me deja pensando

Trabajo con servidores y con hierro viejo suficiente para saber que este tipo de bugs existen en todas partes. Lo que me impresiona no es que Apple tenga un erratum —todos los fabricantes tienen errata, están en los PDFs de Intel que nadie lee— sino que nadie dentro de Apple lo haya detectado. El ANE es la pieza que supuestamente hace mágico al MacBook para IA local, y llevaba años funcionando a un tercio de velocidad en cargas concretas. El benchmark de marketing dice 100 GB/s de memoria unificada y todos aplauden; el caso real con pesos que caen en una frontera de página era otra historia.

La lección para cualquiera que haga ingeniería de sistemas: mide vos mismo. Los números que entrega el vendor son la mejor hipótesis, no la verdad. Y si algo va lento sin explicación, la respuesta puede estar a nivel de controlador de memoria, no en tu código. Cachai que la próxima vez que tu modelo local corra lento quizás no es tu pega, es un contador de 14 bits dando la vuelta en el DMA del Neural Engine.

Fuente de inspiración: Getting 50 GB/s Back Out of the ANE

Comentarios

Aún no hay comentarios. ¿Por qué no comienzas el debate?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *