rpc: support apple RDMA as an RPC transport - #26421
Conversation
|
benchmarks for Unsloth's Qwen 3.6 27B Q4_K_XL for something more practical: cli: workers: TCP Baseline
Apple RDMA
Performance vs TCP
|
|
Another datapoint, using https://huggingface.co/ggml-org/DeepSeek-V4-Flash-0731-GGUF . I don't have hardware to test a 1 node baseline so pulled that from @ggerganov 's result here I'm unable to test with >2 nodes because deepseek v4 fails to init with 3, 4 RPC backends currently.. Apple RDMA
TCP
Performance vs TCP
cc @rgerganov given this is RPC work, let me know if there's anything I can do to move this forward. Been daily driving this for a few weeks now with other models. |
|
@ryan5rdx None of the current maintainers has Macs with RDMA connection, so it might be a while before we can review these changes properly. If you are interested in helping with maintaining the RDMA transport implementation, I can invite you as a maintainer of the RPC backend. With the ongoing work in #26610 we can use your help with testing and fixing issues on Apple clusters. LMK |
sure feel free to add me - happy to help test where I can. |
rgerganov
left a comment
There was a problem hiding this comment.
thanks for the patch; I don't have the hardware to test this but I am fine accepting this as long as it doesn't change the transport interface without good reasons and doesn't break the linux implementation
c7b1b67 to
7cdd3fe
Compare
|
@rgerganov thanks for the review! Reverted the set_tensor optimization + socket pinning, quick smoke test resulted in same performance, so they didn't seem to be doing much anyway. |
| @@ -308,7 +311,7 @@ static bool send_rpc_cmd(socket_ptr sock, enum rpc_cmd cmd, const void * input, | |||
| if (!sock->send_data(input, input_size)) { | |||
| return false; | |||
| } | |||
| return true; | |||
| return sock->flush(); | |||
There was a problem hiding this comment.
can you try to measure the performance impact of having an explicit flush()? i.e. flushing on every send vs manual flushing like here
There was a problem hiding this comment.
measured - without this manual flush the coalesing breaks somewhat (we end up sending ~two more empty TB frames per RPC command).
flushing on every send: 21.17 t/s tg 2048
manual flush: 22.41 t/s tg 2048
prefill appears to be a little slower, but within ~margin of error 290 vs ~282 t/s pp2048
rgerganov
left a comment
There was a problem hiding this comment.
no CI build with RPC enabled is currently triggered on MacOS; please fix build-apple.yml to trigger CI builds on changes in ggml/src/ggml-rpc/**
|
arm64 apple build looks good - I see other apple failures (x86, tvos?) but those look like infra issues, and I can't seem to retrigger (though I'm not sure if those should work anyway): |
|
@rgerganov let me know if there's anything I can do here! |
rgerganov
left a comment
There was a problem hiding this comment.
I am fine to merge this, just need to do some final testing on the spark cluster that I have. I'm travelling this week, will post updates after 15th. Thanks.
|
@rgerganov thanks! Hoping to merge this soon! Once this is in I plan to also put a PR up to support similar polled-release fence to what I've put up here: antirez/ds4#743 which should result in some additional big reductions in apple TB RPC latency |
|
@rgerganov sorry to keep prodding here! Maybe @ggerganov could take a look? Looking forward to brining the metal RPC topology up to speed, esp now that #26490 has landed! |
|
@ryan5rdx Could you rebase the branch on latest |
a8e7767 to
0de310d
Compare
|
This change renders llama.cpp not working anymore in MacOS Sequoia: ❯ ./llama-server --list-devices
dyld[52025]: Library not loaded: /usr/lib/librdma.dylib
Referenced from: <8884FFC7-AE3A-31EE-9433-58C08295B8FA> /Users/srigi/Downloads/llama-b10628/libggml-rpc.0.22.0.dylib
Reason: tried: '/usr/lib/librdma.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/usr/lib/librdma.dylib' (no such file), '/usr/lib/librdma.dylib' (no such file, not in dyld cache)
[1] 52025 abort ./llama-server --list-devicesYou pretty much locked all Sequoia users to the previous version without any future updates. |
opps sorry - mind testing #27815 ? |
Your branch compiled successfully and is working OK. Thank you.
|
|
@ryan5rdx Have you seen this error when running with RDMA:
|
could you send your command? and hardware? IIUC this error is cosmetic( RDMA buffer/QP cleanup on destroy), so I suspect your workflow is creating/destroying many RDMA sockets over and over, I'll look into it once I have the repro. I used to see it on llama-cpp server/cli shutdown sometimes as I was developing |
|
On MacBook M5 Max 48GB: ./bin/ggml-rpc-server --host 0.0.0.0 --port 50052 -d MTL0 -cOn MacBook M5 Max 128GB: ./bin/llama-server -hf ggml-org/Qwen3.8-27B-GGUF:Q8_0 --rpc 192.168.100.1:50052 --host 0.0.0.0 --port 8044 -lv 4 -c 65536 |
#27908 should address this - doing some final tests now. |
* rpc: support apple RDMA as an RPC transport * remove set_tensor micro optimization, rpc socket pinning per CR * remove transparent reconnect * trigger apple builds on RPC changes --------- Co-authored-by: Ryan Churaman <rschu@meta.com>
|
What would be great is to revisit the decision of having to push all tensors from the server to worker nodes on cold start. It would be much better if one could distribute GGUF files to every node with a worker and only send metadata from the server to workers. I've been experimenting with custom TCP over JACCL before I learned about this PR and in all my experiments it still takes minutes before a model is distributed. I know about the cache but in certain cases cache might not be preferred. Instead, workers should be able to hold their copy of the model, the server should be telling the worker "these tensors from this GGUF need to be loaded", and the worker should simply trust the server. The main bottleneck appears to be sequential processing of every byte, and tensor reconstruction on the other side. I'd be happy to help getting that in, I also can help testing on 4x M3 Ultra. I bet this would also solve this problem #28126. Great to see this landing here, though! /cc @ggerganov @ryan5rdx |
I really think this would be a great idea i like this do you have a request you have made for this i can add my vote to it |



Overview
Extending the RPC transport layer to support Apple's RDMA implementation (alongside the existing linux one). A lot of the implementation details here are the result of what's outlined in Apple's tech note TN3205, while trying to stay as close to the existing linux implementation as possible. IIUC, the linux RDMA path should be unchanged, but I don't have linux hardware to test so would appreciate someone verifying that everything (still)works fine there.
Additional information
From the inline comment: the core differences in this implementation vs linux RDMA are:
on Apple a SEND and its corresponding RECV must cover the same number of 4 KiB Thunderbolt frames, so every SEND posts a whole 128KiB stride over the wire, even when partially filled. (In testing 128KiB was the best performing among 32, 64, 128, 256)
There are some micro optimizations included here per AI suggestion (eg. no flush on RPC_CMD_SET_TENSOR for coalescing, forcing a flush on
ggml_backend_rpc_synchronize) In testing they didn't seem to improve much, but leaving them in for now because they seem harmless+correct 🙃Testing
Testing with Qwen3-0.6B-UD-Q4_K_XL.gguf, M3 Ultra, layer parallel:
TCP baseline
Apple RDMA
Performance vs TCP
These numbers are so high because for this tiny model the RPCs are a big chunk of the per-token-time relative to compute - I'll try to also try to benchmark with qwen3.6 27B shortly
Note that when testing - on workers with multiple active TB interfaces (often the case), pass the one connected to your client via the GGML_RDMA_DEV env var, eg:
Requirements