메뉴
HN
Hacker News 16일 전

M4 맥북 에어에 RTX 5090을 연결한다면?

IMP
7/10
핵심 요약

이 글은 썬더볼트 eGPU를 통해 M4 맥북 에어에 데스크톱용 GPU인 엔비디아 RTX 5090을 연결해 게임과 AI 추론을 구동하는 실험을 다룹니다. 애플 실리콘의 한계를 우회하기 위해 macOS 호스트 위에서 64비트 ARM 아키텍처 기반의 Linux 가상 머신(VM)을 구성하고 PCI 패스스루(Passthrough) 기술을 적용하여 엔비디아 GPU를 할당하는 기술적 과정을 상세히 설명합니다. 이는 얇은 노트북에서도 외부 GPU를 통해 고성능 그래픽 및 AI 연산이 가능함을 증명하는 흥미로운 엔지니어링 사례입니다.

번역된 본문

목차 절대 불가능하다고 말하지 마세요 썬더볼트 eGPU란 무엇인가요? tinygrad는 어떨까요? 기존 Linux 드라이버 macOS에서의 PCI 패스스루 엔지니어링 PCI 장치 기본 사항 PCI BAR 매핑 DMA (Direct Memory Access) Apple Silicon에서의 DMA apple-dma-pci NVIDIA 정렬 특이점(quirk) 매핑 병합(Coalescing mappings) 기타 성능 관련 사항 스케줄링 전체 저장소 순서 보장(Total store ordering) 벤치마크 (CPU 비교, 사이버펑크 2077 720p Low / 1080p / 4K, 정리, GravityMark, 쉐도우 오브 더 툼 레이더, 호라이즌 제로 던 리마스터드, 둠 2016, 크라이시스를 돌릴 수 있을까요?) AI 추론 (Qwen 3.6, Gemma 4, 이것을 실행할 수 있을까요?) 알림 받기 결론 및 후속 작업, 크레딧

만약 당신의 맥북 에어에 완전한 데스크톱용 GPU를 장착할 수 있다면 어떨까요? 놀랍게도, 가능합니다. (간단한 FTC 필수 고지사항: 제 링크를 통해 구매하시면 저에게 약간의 수수료가 지급될 수 있습니다.)

절대 불가능하다고 말하지 마세요 # 인정하기 싫지만, 요즘 제 프로젝트의 첫 번째 단계는 대개 AI에게 그것에 대해 묻는 것입니다. 어쩌면 내가 모르는 무언가를 알려줄 수도 있으니까요. 다행히도, '실용성이 거의 없는 한계선에 있는 것'이 제 전문 분야와 비슷합니다.

썬더볼트 eGPU란 무엇인가요? # 자, 계획은 대형 PC 게임용 GPU인 NVIDIA RTX 5090을 제 M4 맥북 에어에 연결하는 것입니다. 그러려면 PCIe를 썬더볼트로 변환해 주는 썬더볼트 독에 GPU를 꽂고, 이를 다시 USB-C 포트에 연결해야 합니다. 썬더볼트는 USB-C 케이블을 통해 PCIe를 터널링하므로, 컴퓨터 관점에서 썬더볼트 장치는 USB 장치가 아니라 실제 PCIe 장치입니다. 썬더볼트 4에서는 터널링에 대한 약간의 성능 저하를 감수하면 최대 40Gbps의 속도를 제공하는 4개의 PCIe 레인을 사용할 수 있습니다. USB4에도 이와 동일한 PCIe 터널링이 선택적 기능으로 포함되어 있으므로, 썬더볼트가 아닌 일부 USB4 포트에서도 이 작업을 수행할 수 있습니다. 이를 통해 호환되는 포트가 있는 노트북에 GPU를 연결할 수 있습니다. 컴퓨터 입장에서는 장치가 약간 느린 PCIe 장치처럼 보이기 때문에 일반적으로 해당 장치에 사용하는 것과 동일한 드라이버를 그대로 사용할 수 있습니다. eGPU는 Linux 및 Windows에서 거의 바로 사용할 수 있습니다. (비록 썬더볼트가 아닌 Oculink를 사용해야 하지만) 라즈베리 파이에서도 eGPU를 사용하는 것이 가능합니다. 첫 번째 장애물은 macOS가 Apple Silicon 환경에서 NVIDIA 또는 AMD GPU용 드라이버를 기본적으로 제공하지 않는다는 것입니다.

tinygrad는 어떨까요? # tinygrad는 최근 자체적인 macOS eGPU 드라이버를 출시했습니다. 이는 NVIDIA 및 AMD 하드웨어를 위한 자체 오픈소스 드라이버 파이프라인을 갖춘 완전히 새로운 AI 스택입니다. 안타깝게도, 당신의 주요 목적이 AI 추론을 실행하거나 게임을 즐기는 것이라면 tinygrad는 아마도 당신이 찾고 있는 해결책이 아닐 것입니다. 유튜버 Alex Ziskind의 영상에 따르면 eGPU를 통해 tinygrad를 사용하여 추론하는 것은 eGPU가 없는 M4 Pro에서 직접 네이티브 Metal 추론을 실행하는 것보다 약 10배 느립니다. tinygrad eGPU 드라이버는 tinygrad 스택에서만 사용할 수 있으며 다른 용도로는 사용할 수 없습니다. 또한 지원하는 AI 모델도 매우 제한적입니다. GPU에서 NVIDIA PTX 코드를 실행하는 것과 임의의 소프트웨어와 함께 작동하는 완전한 범용 디스플레이 드라이버를 작성하는 것은 완전히 다른 이야기입니다. 후자가 훨씬 더 어려운 문제입니다. 그렇다면 지금 당장 eGPU와 맥으로 무엇을 할 수 있을까요?

기존 Linux 드라이버 # 이제 Apple Silicon 맥에서도 Linux를 실행할 수 있습니다. 안타깝게도 현재 Linux 커널은 Apple Silicon에서 썬더볼트를 지원하지 않습니다(내부 장치 및 USB3만 지원). 하지만... macOS 호스트 위에서 64비트 ARM VM(가상 머신)으로 Linux를 실행할 수는 있습니다. macOS는 썬더볼트 장치를 지원하고 Linux는 NVIDIA GPU를 지원합니다. 이 조각들을 모아 GPU를 Linux VM으로 패스스루(통과)시켜 봅시다. 개념적으로 우리는 단순히 GPU를 Linux VM 안에 넣을 것입니다. VM은 Mac 호스트와 동일한 아키텍처(arm64)를 사용하므로 성능도 비슷할 것입니다. 물론 악마는 디테일에 숨어 있습니다. 참고로 ARM64 Windows용으로는 NVIDIA 카드용 드라이버가 존재하지 않습니다. 그렇기 때문에 우리가 Linux를 사용하는 이유입니다. 결과물에 대한 빠른 비디오 데모를 보려면 이 영상을 확인해 보세요: 이 글의 나머지 부분에서는 이것을 실제로 작동시키기까지의 길고 험난한 과정을 살펴보겠습니다. 스크린샷과 벤치마크만 보고 싶다면 바로 벤치마크 섹션으로 건너뛰어도 좋습니다.

macOS에서의 PCI 패스스루 엔지니어링 # PCI 장치 기본...

원문 보기
원문 보기 (영어)
Table of Contents Never tell me the odds What&rsquo;s a Thunderbolt eGPU? What about tinygrad? The existing Linux driver Engineering PCI Passthrough on macOS PCI device basics Mapping PCI BARs DMA DMA on Apple Silicon apple-dma-pci NVIDIA alignment quirk Coalescing mappings Other performance concerns Scheduling Total store ordering Benchmarks CPU comparison Cyberpunk 2077 720p Low 1080p 4K Takeaways GravityMark Shadow of the Tomb Raider Horizon Zero Dawn Remastered Doom (2016) Can it run Crysis? AI Inference Qwen 3.6 Gemma 4 Can I run this? Get notified Conclusion Follow-on Credits What if you could strap a full desktop GPU to your MacBook Air? Turns out, you can. Just a quick FTC required note: When you buy through my links, I may earn a commission. Never tell me the odds # As much as I hate to admit it, step one in most of my projects now is to ask AI about it. Maybe it&rsquo;ll tell me something I don&rsquo;t know. Fortunately, borderline-impractical is kind of my thing. What&rsquo;s a Thunderbolt eGPU? # Ok, so the plan is to plug a big PC gaming GPU, an NVIDIA RTX 5090, into my M4 MacBook Air. To do that, we plug it into a Thunderbolt dock which adapts PCIe to Thunderbolt, and we plug that into a USB-C port. Thunderbolt tunnels PCIe over a USB-C cable, so from the computer&rsquo;s perspective a Thunderbolt device really is a PCIe device, not a USB one. You get 4 PCIe lanes at up to 40Gbps on Thunderbolt 4, with a small performance penalty for the tunneling. USB4 includes the same PCIe tunneling as an optional feature, so some non-Thunderbolt USB4 ports can do this too. You can use this to plug a GPU into a laptop with a compatible port. From the computer&rsquo;s perspective, the device looks more or less like a slightly slower PCIe device, so you can usually use the same drivers you&rsquo;d normally use for those devices. eGPUs work pretty much out of the box on Linux and Windows. It&rsquo;s even possible to use one on a Raspberry Pi (albeit with Oculink , not Thunderbolt). The first hurdle is that macOS does not ship with drivers for NVIDIA or AMD GPUs on Apple Silicon. What about tinygrad? # tinygrad recently released their own macOS eGPU drivers . It&rsquo;s a whole new AI stack with its own open source driver pipeline for NVIDIA and AMD hardware. Sadly, if your main objective is to run AI inference or play games, tinygrad probably isn&rsquo;t the solution you&rsquo;re looking for. This video by YouTuber Alex Ziskind shows that using an eGPU via tinygrad for inference is about 10 times slower than running native Metal inference directly on an M4 Pro without an eGPU. You can only use the tinygrad eGPU driver with the tinygrad stack, not for anything else. It also has very limited support for different AI models. Getting NVIDIA PTX code running on the GPU is one thing. Writing a full general-purpose display driver that works with arbitrary software is a significantly harder problem. So for now, what can you actually do with an eGPU and a Mac? The existing Linux driver # Linux can run on Apple Silicon Macs now . Regrettably, at this time, the Linux kernel does not support Thunderbolt on Apple Silicon (only internal devices and USB3). But&mldr; You can run Linux in a 64-bit ARM VM on a macOS host. macOS supports Thunderbolt devices. Linux supports NVIDIA GPUs. Let&rsquo;s put the pieces together and pass through the GPU into the Linux VM. At a high level, we&rsquo;re just going to put the GPU in the Linux VM. The VM is the same architecture as the Mac host (arm64), so performance should be comparable. Of course, the devil is in the details. There is no driver for NVIDIA cards on ARM64 Windows. That&rsquo;s why we use Linux. For a quick video demo of the result, take a look: In the rest of the post, I&rsquo;ll go through the long and winding road of getting this to actually work. If you just want to see screenshots and benchmarks, you can probably skip to the benchmark section . Engineering PCI Passthrough on macOS # PCI device basics # Let&rsquo;s look at two things we need working for the VM to talk to the PCI device: PCI BAR (Base Address Registers) - Each PCI device communicates through chunks of memory that the computer can read and write to. There&rsquo;s basically a reserved region of memory on your computer for each device. Those memory regions have to be mirrored into the VM for PCI passthrough to work. DMA (Direct Memory Access) - This is how the device can read and write information directly in/out of your computer&rsquo;s memory. Instead of having the CPU burn cycles copying data from the device, the device can copy the memory automatically. For a GPU, it might be used to copy textures directly from the computer&rsquo;s memory into its own video memory. Mapping PCI BARs # When QEMU starts a VM, it sets up the guest&rsquo;s memory layout. For normal RAM, this boils down to a call to hvf_set_phys_mem() in QEMU, which uses the Hypervisor.framework method: hv_vm_map (mem, guest_physical_address, size, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC); Next, we connect to the host PCIDriverKit driver and ask to map the memory from the PCI device into our process. (I&rsquo;m leaving the driver-side code out for now, but it&rsquo;s very similar boilerplate.) // map BAR0 into the current process and set `addr` to the location // where it was mapped mach_vm_address_t addr = 0 ; mach_vm_size_t size = 0 ; IOConnectMapMemory64 (driverConnection, 0 , mach_task_self (), & addr, & size, kIOMapAnywhere); Ok, so then we have addr , which now points to the BAR0 memory that we can access directly in our process. At this point you can just read and write stuff to it, like any other piece of memory. volatile uint32_t * bar0 = ( volatile uint32_t * )addr; printf ( &#34;BAR0[0] = %x \n &#34; , bar0[ 0 ]); // this would output: BAR0[0] = 0x1b2000a1 // which is a device-specific constant that describes my RTX 5090 // // BAR0[0] is the BOOT_0 register. The fields break down as: // arch = 0x1b → GB200 GPU family // impl = 0x2 → GB202 die (RTX 5090) // major_rev = 0xa → stepping A // minor_rev = 0x1 → revision 1 (together: stepping A1) Now we just make sure QEMU calls hvf_set_phys_mem() for our device memory, and we can map that into the guest. When guest code touches that mapping, it talks directly to the GPU with minimal host overhead. This is the best case for performance. At least, in theory. In practice, as soon as the VM touched the PCI BAR memory, the host kernel crashed. If you&rsquo;ve never experienced this before, it&rsquo;s disorienting. Your entire computer will hang, and because the trackpad feedback is controlled by software, suddenly the trackpad will no longer click. The dogs and cats in your neighborhood start howling. Pictures fall off the walls of your house. Eventually your computer will reboot, and you will be presented with this dialog. Ok, so we can&rsquo;t map device memory directly, but we have other tricks up our sleeve. We can trap every access to the memory, exit the guest back into QEMU, and have QEMU forward each read or write to the device. That keeps behavior correct, but it&rsquo;s brutally slow. In many workloads the pain is elsewhere. Most of the performance-sensitive work is DMA, but some paths still care how fast you can push commands through the BAR. I started preparing a bug report for Apple and wrote a small reproduction (well, AI-assisted) to demonstrate the issue: #include <Hypervisor/Hypervisor.h> #include <IOKit/IOMapTypes.h> #include <libkern/OSCacheControl.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define FAIL(code) do { result->status = (code); goto cleanup; } while (0) #define HV_CHECK(expr, code) do { \ if ((expr) != HV_SUCCESS) FAIL(code); \ } while (0) #define PREFETCHABLE_MASK 0x08 #define SELECTOR_GET_BAR_INFO 10 #define GUEST_CODE_IPA 0x4000ULL #define GUEST_BAR_IPA 0x10000000ULL static const uint32_t prog_read[] = { 0xf9400001 , /* ldr x1, [x0] */ 0xd4000002 , /* hvc #0 */ 0xd4200000
관련 소식