RTX 5090 y la MacBook Air con M4: ¿se puede jugar?
(scottjg.com)- Se conectó una eGPU RTX 5090 a una MacBook Air con M4 y se ejecutaron juegos en una VM de Linux, teniendo que esquivar la falta de drivers en macOS y las limitaciones de Thunderbolt
- La implementación requirió un dispositivo PCI virtual
apple-dma-pci, evasión del mapeo DART, parches del driver de NVIDIA basados en kprobes y modificaciones a QEMU/HVF - Cyberpunk 2077 en una M4 Air + eGPU logró 27 fps en 4K RT Ultra y subió hasta 111 fps con generación de cuadros DLSS, volviéndose jugable
- Si se conecta la misma RTX 5090 a una PC común por PCIe, resulta de 2 a 4 veces más rápida según el juego, y sigue habiendo bastante sobrecarga por FEX, Proton, la VM y Thunderbolt
- El logro más grande fue en inferencia de IA: el prefill de Qwen en la M4 Air se redujo cerca de 100 veces y la generación de un solo stream subió de unas 22 tok/s a 155 tok/s
Limitaciones de las eGPU por Thunderbolt y las Mac Apple Silicon
-
Estructura de una eGPU por Thunderbolt
- El método consiste en conectar una GPU de escritorio como la RTX 5090 a un dock Thunderbolt, y que el dock convierta PCIe a Thunderbolt para enlazarlo al puerto USB-C de la MacBook Air con M4
- Como Thunderbolt tuneliza PCIe sobre un cable USB-C, para la computadora el dispositivo Thunderbolt no se ve como un USB sino como un dispositivo PCIe
- Thunderbolt 4 ofrece hasta 40 Gbps con 4 lanes PCIe, con una pequeña pérdida de rendimiento por el tunelizado
- Normalmente, en Linux y Windows una eGPU se reconoce como un dispositivo PCIe un poco más lento y casi funciona de inmediato con los drivers existentes
- El primer obstáculo es que macOS en Apple Silicon no incluye por defecto drivers para GPUs de NVIDIA ni AMD
-
Rodeo mediante una VM de Linux
- Es posible ejecutar Linux en Macs Apple Silicon, pero el kernel de Linux actual todavía no soporta Thunderbolt en Apple Silicon y solo soporta dispositivos internos y USB3
- Si se ejecuta una VM de Linux ARM de 64 bits sobre un host macOS, se puede combinar que macOS maneje el dispositivo Thunderbolt y Linux maneje la GPU NVIDIA
- Se usa Linux porque no existen drivers de tarjetas NVIDIA para Windows ARM64
- El driver eGPU de tinygrad para macOS solo sirve dentro del stack de tinygrad, así que no encajaba como driver general para inferencia de IA o para ejecutar juegos
Implementación de passthrough PCI en macOS
-
PCI BAR y DMA
- Para que una VM se comunique con un dispositivo PCI, deben funcionar tanto los PCI BAR (Base Address Registers) como DMA
- Los PCI BAR son regiones de memoria que el dispositivo PCI usa para leer y escribir con la computadora, y para que el passthrough PCI funcione hay que reflejar esas regiones dentro de la VM
- DMA (Direct Memory Access) es el mecanismo por el que el dispositivo lee y escribe directamente en la memoria del sistema sin copiar por CPU
-
Hypervisor.framework y mapeo de BAR
- Al iniciar la VM, QEMU llama a
Hypervisor.frameworkmediantehv_vm_map()para establecer el layout de memoria del guest - Al conectarse al driver host de PCIDriverKit y mapear la memoria del dispositivo PCI al proceso con
IOConnectMapMemory64(), se puede leer la memoria BAR0 - Al leer
BAR0[0]aparece0x1b2000a1, una constante específica del dispositivo que apunta a la RTX 5090 - Si QEMU mapea directamente la memoria del dispositivo al guest, el guest puede comunicarse directamente con la GPU, pero al principio el kernel host se caía apenas la VM tocaba la memoria PCI BAR
- La causa era que QEMU añadía
HV_MEMORY_EXECtambién al mapeo de RAM-device/MMIO, y se evitó el panic del host con un workaround que eliminaEXECde los mapeos de device/MMIO - Este método es unas 30 veces más rápido que interceptar cada acceso, pero como
hv_vm_map()no puede indicar el subtype de memoria de dispositivo ARM, las escrituras al BAR son cerca de 10 veces más lentas de lo normal
- Al iniciar la VM, QEMU llama a
Cómo se esquivaron las limitaciones de DMA y DART
-
Límites de DART en Apple Silicon
- Apple Silicon tiene una unidad de hardware DART similar a una IOMMU, que también funciona como barrera de seguridad para impedir que un dispositivo acceda a memoria arbitraria del host
- Al usar un dispositivo Thunderbolt a través de PCIDriverKit, hubo tres limitaciones importantes
- Un límite de mapeo de ~1.5 GB impide dejar tal cual los mapeos de memoria de 8–16 GB que necesitan CUDA y los juegos modernos
- Un tope de ~64k mapeos hace que la tabla se llene si hay muchos buffers DMA pequeños
- No se puede elegir directamente la dirección ni el alignment, así que no encaja bien el enfoque de IOMMU virtual donde el guest decide la dirección DMA
- Forzar DMA a una región preasignada con
restricted-dma-poolfuncionó con dispositivos simples, pero no con el driver de GPU
-
Dispositivo PCI virtual
apple-dma-pci- Se añadió a QEMU un dispositivo PCI virtual llamado
apple-dma-pciy se insertó en la VM junto con la GPU pasada por passthrough - Un driver del kernel guest intercepta las llamadas de mapeo DMA del driver de NVIDIA, crea mapeos bajo demanda para cada solicitud DMA y los libera cuando se libera el buffer
- Con esta estructura, no hace falta que toda la RAM del guest entre en el límite de 1.5 GB, sino solo el conjunto activo de buffers DMA de ese momento
- El driver guest reemplaza al driver de NVIDIA por unas operaciones DMA personalizadas antes de usar la GPU, y procesa
map_page,unmap_page,map_sg,unmap_sg,allocyfreemediante wrappers ligeros - Del lado host, QEMU pasa la solicitud al driver de PCIDriverKit, que realiza el mapeo real en DART y luego vuelve a escribir la dirección DMA en la memoria del guest
- Se añadió a QEMU un dispositivo PCI virtual llamado
-
Problema de alignment de NVIDIA y parche con kprobes
- Al ejecutar cargas de trabajo CUDA aparecieron en el log del kernel
NV_ERR_INVALID_OFFSETy mensajes relacionados con el alignment deRM_PAGE_SIZE_HUGE - La asignación problemática era una asignación de 16 MB de tipo
UVM_RM_MEM_TYPE_SYS, y el driver de NVIDIA usaba tamaño de página de 2 MB, chocando con las restricciones de alignment - El driver ya tenía un workaround para reintentar con el tamaño de página por defecto cuando fallaba con
NV_ERR_NO_MEMORY, pero no manejabaNV_ERR_INVALID_OFFSET - Usando kprobes del kernel Linux, se forzó
pageSizeaUVM_PAGE_SIZE_DEFAULTen la llamada anvUvmInterfaceMemoryAllocSys() - Así se logró que pidiera páginas más pequeñas sin modificar directamente el driver de NVIDIA, y las cargas de trabajo simples pudieron funcionar
- Al ejecutar cargas de trabajo CUDA aparecieron en el log del kernel
-
Coalescing de mapeos para evitar el tope de 64k
- Al subir la calidad gráfica aparecían muchos mapeos diminutos y se superaba el límite de ~64k mapeos
- En el log de mapeo, más del 90% eran de 4 kB y, aunque no eran contiguos, sí aparecían en forma de clusters
- Se dividió la memoria guest en regiones de tamaño fijo, como 256 kB, y cuando se mapeaba un buffer de 4 kB se mapeaba todo el cluster correspondiente para que futuras asignaciones del mismo cluster reutilizaran el mapeo existente
- Este enfoque mapea un poco más de memoria que los buffers activos reales, pero en las cargas probadas se mantuvo bajo el techo de ~1.5 GB
- La cantidad de mapeos activos se redujo alrededor de 4 veces, abriendo margen para ejecutar juegos exigentes en ajustes máximos
Mejoras de rendimiento de la VM
-
Programación de vCPU
- Había un problema en el que las puntuaciones de benchmark variaban mucho al azar y a veces salían hasta 50% más lentas
- Parecía que QEMU no asignaba prioridad a los threads de vCPU y el scheduler no daba suficiente tiempo de ejecución a la VM
- Se aplicó un parche en la ruta de arranque de vCPU de QEMU para dar alta prioridad con
pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0)ypthread_setschedparam(..., SCHED_RR, ...)
-
Total Store Ordering y FEX-Emu
- La VM corre Linux arm64, pero la mayoría de los juegos comerciales siguen siendo binarios x86-64 para Windows, así que se usan juntos Proton) y FEX-Emu
- x86 usa Total Store Ordering (TSO), en el que los stores se observan por otros cores en el orden del programa, mientras que ARM usa un modelo de ordenamiento de memoria más débil
- Apple Silicon tiene un modo TSO por thread a nivel de hardware, y
Hypervisor.frameworklo expone en macOS 15+ - Se tomó un parche de UTM para activar el bit 1 de
ACTLR_EL1en la vCPU y desactivar la emulación TSO por software de FEX-Emu - Si se desactiva la emulación TSO por software sin ese bit de hardware, Geekbench 6 se cae a mitad de ejecución
- El rendimiento del guest usando FEX y TSO de CPU queda cerca de 50% por debajo del rendimiento nativo del host
Rendimiento en juegos
-
Cyberpunk 2077
- Cyberpunk 2077 se probó en una M4 Air con macOS nativo, una M4 Air + eGPU, una Intel MacBook Pro 2020 + eGPU, una M5 Max con macOS nativo, una M5 Max + eGPU y una PC gamer con i5-12600K + RTX 5090
+ Framegenusa DLSS 4x en las configuraciones con eGPU/PCIe nativo, y FSR 2x en las configuraciones macOS nativas- En 720p Low, la carga de GPU era baja y dominaban el CPU y la sobrecarga de emulación/virtualización, por lo que la M4 Air nativa con 61 fps fue más rápida que la M4 Air + eGPU con 49 fps
- En 1080p High, la M5 Max nativa en macOS alcanzó 131 fps frente a 68 fps de la M5 Max + eGPU, mostrando que cuando la GPU integrada alcanza, la sobrecarga pesa más
- La M4 Air nativa en macOS se quedó en 7 fps en 1080p RT Ultra, pero la M4 Air + eGPU logró 30 fps, y 119 fps con generación de cuadros
- En 4K, el cuello de botella pasa a ser la GPU, y la M4 Air + eGPU registró 27 fps en RT Ultra y 111 fps con generación de cuadros DLSS, llegando a un nivel jugable
- La PC gamer con PCIe nativo fue la más rápida con 100 fps en 4K RT Ultra y 282 fps con generación de cuadros DLSS
- La M5 Max + eGPU obtuvo 47 fps en 4K RT Ultra y 145 fps con generación de cuadros, aproximadamente 30–70% por encima de la M4 Air + eGPU
-
Otros juegos y benchmarks
- En GravityMark, conectar la misma GPU por Thunderbolt en vez de por slot PCIe redujo el rendimiento cerca de 20%, y la M4 Air + eGPU fue alrededor de 31% más lenta que la conexión PCIe nativa
- En Shadow of the Tomb Raider, la eGPU elevó la M4 Air de 8 fps nativos en 4K a 40 fps, y en 1080p también mejoró de 26 fps nativos a 42 fps con eGPU
- En Shadow of the Tomb Raider, el rendimiento de la eGPU fue casi igual en 1080p y 4K, revelando que el cuello de botella no era la GPU sino el CPU corriendo bajo FEX
- Horizon Zero Dawn Remastered no pudo iniciar el benchmark porque incluso en 720p mínimo exigía más de 1.5 GB de mapeo de memoria DMA a la vez
- Doom (2016) sí funcionó en la configuración con eGPU, mostró 49 fps en el overlay de rendimiento y siempre se mantuvo por encima de 30 fps
- Crysis Remastered fue hasta unas 4 veces más lento que en la PC gamer, pero aun así corrió con framerate jugable en una M4 MacBook Air
Rendimiento en inferencia de IA
-
Qwen 3.6
- Se probó el modelo Qwen 35B MoE cuantizado a 4 bits, con 3B de parámetros activos
- En la GPU NVIDIA se usó vLLM con la versión NVFP4, y en Apple Silicon se usó vllm-mlx con un modelo MLX cuantizado a 4 bits
- El benchmark se ejecutó con
llama-benchy - La eGPU por Thunderbolt perdió cerca de 9% frente a PCIe, pero como casi todo el trabajo ocurre en la tarjeta, quedó bastante cerca de PCIe
- La RTX 5090 fue 6.5 veces más rápida que la M4 Air, 2.1 veces más rápida que la M4 Max Mac Studio y 1.2 veces más rápida que la M5 Max MacBook Pro en generación de un solo stream
- Con un prompt de 4K tokens, la M4 MacBook Air tardó 17 segundos en el prefill, pero al añadir la eGPU al mismo equipo bajó a 150 ms, o sea unas 120 veces más rápido
- Al aumentar las solicitudes concurrentes de 1 a 4, el throughput total de la configuración RTX 5090 subió alrededor de 3 veces, mientras que las Mac Apple Silicon escalaron menos
-
Gemma 4
- Gemma 4 31B no es un MoE disperso sino un modelo denso de 31B, por lo que cada token debe pasar por todos los parámetros
- La GPU integrada de la M4 Air no pudo superar 2–3 tokens por segundo durante la prueba, así que quedó fuera de un rango útil
- Todas las configuraciones RTX 5090 basadas en vLLM se agruparon en ~50 t/s con apenas unos puntos porcentuales de diferencia, mientras que la M4 Max Mac Studio logró ~22 t/s y la M5 Max MacBook Pro ~27 t/s
- También en prefill la RTX 5090 siempre estuvo por debajo de 400 ms, mientras que la M4 Max tardó hasta 21 segundos en procesar un prompt de 4K tokens y la M5 Max alrededor de 7.5 segundos
- Las configuraciones vLLM marcaron un throughput de alrededor de 3.5 veces con 4 solicitudes concurrentes, mientras que el backend MLX de Mac casi no aumentó más al llegar a 4 solicitudes
Posibilidad de uso directo y estabilidad
-
Despliegue y requisitos de compilación
- En su estado actual, esto todavía no está al nivel de “descargar y ejecutar” y requiere un entitlement especial de Apple
- Ya se solicitó ese entitlement, pero todavía no ha llegado respuesta y la espera podría durar meses
- Mientras tanto, el driver puede compilarse manualmente y esa Mac debe estar incluida en la cuenta del certificado de firma
- No hace falta desactivar SIP ni usar reduced security mode
- El código está disponible en qemu-vfio-apple
- El launcher incluido descarga automáticamente una imagen precompilada de Ubuntu con el driver especial
apple_dmainstalado
-
Estabilidad
- La estabilidad todavía no es buena
- FEX tiene actualmente un bug por el que Steam se cae seguido en bucle, y en esta configuración el problema parece peor
- Iniciar ciertos juegos puede tardar varios minutos
- Por el límite de mapeos DMA, los mapeos pueden fragmentarse con el tiempo y dejar sin espacio para ejecutar un juego nuevo
- En ese caso hay que apagar la VM de Linux y desconectar y volver a conectar la GPU para borrar todos los mapeos DMA antes de reintentar
- La tarea más estable es la IA, y para ese uso funciona muy bien
- Se está trabajando en integrar los parches en el upstream de QEMU y el objetivo ideal es que termine incluido en distribuciones principales de QEMU como UTM para que funcione directamente
1 comentarios
Comentarios de Hacker News
Llevo años pidiéndole al equipo de VM passthrough de GPU en VM. Trabajé en Apple Silicon Mac Pro, y habría tenido mucho más sentido si se pudiera hacer passthrough a una VM de Linux de una GPU que entra en el gabinete
Lamentablemente no aceptaron la solicitud, pero está genial que otra gente lo haya hecho funcionar
Al final, parece que solo hace falta que un monitor de máquinas virtuales como QEMU adopte esta interfaz además de algo como Linux VFIO. Si te refieres a Virtualization.framework, eso en sí ya se parece bastante a un monitor de máquinas virtuales, así que me da curiosidad qué es exactamente lo que consideras que le falta a macOS
Hace poco también entró un parche a QEMU mainline para usar un "venus server" junto con virtio-gpu para soportar una capacidad similar en guests Linux bajo Hypervisor.framework. Segundo, parece que dentro de Apple sí existe soporte de passthrough PCI para Virtualization.framework. El código del framework como tal se distribuye a clientes, pero aparentemente depende de kexts o componentes del kernel que no vienen incluidos en macOS común. No sé si planean exponerlo a clientes, pero está claro que dentro de Apple alguien sí pensó en esta función
En cualquier caso, la Mac Pro ya es un producto muerto. Solo con ventas a profesionales de audio y video no alcanza
Excelente artículo. Los benchmarks de juegos son divertidos, pero en términos prácticos la parte realmente interesante es la mejora de rendimiento en LLM
La plataforma de Apple es un entorno accesible y fácil para correr modelos locales gracias a la gran cantidad de RAM, pero a menudo se pasa por alto su velocidad relativamente lenta para procesar prompts. Como cita el artículo, con un prompt de 4K tokens la M4 MacBook Air tarda 17 segundos en parsearlo antes de empezar a generar una respuesta, mientras que con una eGPU termina en 150 ms, o sea 120 veces más rápido. Cuando juegas con LLM usando chats pequeños, el problema del prefill no se nota mucho, pero cuando empiezas a usarlos para tareas más grandes, el límite de cómputo se vuelve el cuello de botella. La gráfica de tiempo hasta el primer token (TTFT) tampoco se ve tan mal al principio, pero cambia de significado cuando ves que la plataforma Mac era demasiado lenta frente al cómputo total de la GPU y por eso tuvieron que graficarla en escala logarítmica
Si el autor presenta los resultados de esta forma puede dar la impresión de sesgo, aunque quiero creer que no es el caso
Parece correcto lo de que OpenGL ya no está bien soportado en macOS y por eso el juego ni siquiera es totalmente jugable con CrossOver
Pero Doom aparentemente soporta Vulkan, y quizá bastaría con añadir
VK_NV_glsl_shadera MoltenVK. Probablemente sea muchísimo menos trabajo que colgarle una RTX 5090 a una M4, pero aun así aplausos para Scott. La velocidad de inferencia local de IA también está bastante buena; es un proyecto realmente de locosBastante impresionante. Yo tenía la impresión de que las eGPU simplemente no funcionan en Apple Silicon
Apple piensa lo mismo. “Para usar una eGPU, necesitas una Mac con procesador Intel.” Además, todas las eGPU oficialmente soportadas eran AMD, no NVIDIA. https://support.apple.com/en-us/102363
Aquí la arquitectura consiste en tunelizar esa eGPU hacia una VM de Linux
Al principio pensé que sería un artículo sobre correr una VM con el driver lento de tinygrad, pero en realidad era un enfoque mucho mejor
Da pena que Apple no lo soporte mejor y no relaje la limitación de ventana de 1.5 GB, porque sería muchísimo más fácil. Arm en general tiene rarezas con dispositivos PCIe, pero al menos en Linux se ha vuelto mucho más sencillo porque la mayoría de los drivers modernos ya tratan a arm64 como ciudadano de primera clase
Mi apuesta es que una razón importante de que tinygrad sea lento es que su motor de inferencia todavía no está muy optimizado para estos modelos públicos de LLM. Supongo que la mayor parte del trabajo ha ido a optimizar el stack de la empresa de hardware para conducción autónoma de George. Como no puedes correr directamente kernels CUDA existentes en ese motor, la dificultad de ingeniería sube muchísimo. También me pregunto si mi proyecto podría compartir con ellos el driver host de macOS. Harían falta algunos cambios, pero parece haber bastante superposición
Esa parte de “el primer paso de la mayoría de los proyectos hoy en día, aunque no queramos admitirlo, es preguntarle a la IA” probablemente significa, más bien, que la IA te va a decir cosas que ni ella sabe
Me acordé de ayer, cuando discutí con ChatGPT sobre si la 5070TI era una tarjeta gráfica real. ChatGPT insistía en corregirme diciendo que esa 5070TI no existía y que seguro me refería a la 4070ti
Le pedí a Claude que hiciera una página HTML sobre PowerShell 7 y escribió que 7.4 era la versión LTS más reciente. Le pasé un enlace diciendo que 7.6 se lanzó en marzo y que la rehiciera con información actualizada, y armó casi la misma página repitiendo la misma afirmación de que 7.4 era la última versión
Aun así, la respuesta de ChatGPT sobre el post original fue completamente acertada. El resumen de “muy profundo”, “casi impráctico” y “desde una perspectiva de investigación” describe perfectamente este artículo
Esto sí está tremendo. Tengo una 5090 sobrante y estoy corriendo claw-like en una M4 Mini; si la conectara en algo como un marco impreso en 3D y la enchufara al puerto TB, podría terminar siendo una herramienta bastante útil para inferencia local
Sí haría falta algún dispositivo que garantice bien cosas como la alimentación eléctrica. El problema es que
max-num-seqsymax-model-lenchocan entre sí, y si no estás en modo estrictamente de un solo cliente, por así decirlo necesitas varios slotsSi logra pasar la aprobación de Apple, parece que podría ser bastante útil para inferencia de IA. Yo quería usar una GPU NVIDIA en una Mac Mini, y con este método sí se podría correr CUDA directamente. Está increíble