如何榨干 Mac 的 GPU 带宽?逐行拆解 llama.cpp 的异步命令编排时序 📅 2026/6/22 0:16:55 在 M2 上把一个 7B 模型的权重交给 GPU 之前,你以为总得先memcpy一遍到显存。可 llama.cpp 的 Metal 后端在最好情况下,为这次"上传"搬运的字节数是0——ggml_metal_buffer_set_tensor进函数第一件事就是判断 buffer 是不是 shared,是就直接memcpy到张量自己的地址然后return(ggml-metal-device.m:1696-1698),根本没有"到显存"这一跳,因为 CPU 和 GPU 本来就在读同一块物理页。你可能会问:数据不"传过去",GPU 内核怎么可能读到对的字节?答案藏在一行newBufferWithBytesNoCopy(ggml-metal-device.m:1511)里。它把 host 用vm_allocate拿到的指针原地包成一个MTLBuffer,CPU 写哪、GPU 读哪是同一处地址;中间没有第二份拷贝。但只要你export GGML_METAL_SHARED_BUFFERS_DISABLE=1,同一个set_tensor立刻退化成"建一个临时 MTLBuffer → 用 blit encoder 拷贝 → 信号量等它完成"(ggml-metal-device.m:1701-1747)——同一行 C 代码,两条命运,快慢差一个数量级。