Skip to content

rpc: support apple RDMA as an RPC transport - #26421

Merged
ggerganov merged 4 commits into
ggml-org:masterfrom
ryan5rdx:ryan5rdx/apple-rdma-transport
Aug 25, 2026
Merged

rpc: support apple RDMA as an RPC transport#26421
ggerganov merged 4 commits into
ggml-org:masterfrom
ryan5rdx:ryan5rdx/apple-rdma-transport

Conversation

@ryan5rdx

@ryan5rdx ryan5rdx commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

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:

  • UC(unreliable connection) on Apple vs RC(reliable connection) QP transport types on Linux (though in practice UC on Apple is still lossless)
  • fixed 128KiB stride on Apple vs variable chunk size on Linux
  • relying on Apple's hardware credit based flow control vs RNR NAKs + retries on Linux

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

Nodes Prefill t/s Decode t/s
1 7620 304.8
2 5296 115.6
3 4498 101.1
4 4007 87.7

Apple RDMA

Nodes Prefill t/s Decode t/s
1 7620 304.8
2 7227 261.3
3 7233 164.2
4 6250 133.5

Performance vs TCP

nodes prefill decode
2 136.46% 226.04%
3 160.80% 162.41%
4 155.98% 152.22%

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:

GGML_RDMA_DEV=rdma_en7 ./bin/ggml-rpc-server   --host 0.0.0.0 --port 50052 -d MTL0 -c 

Requirements

  • I have read and agree with the contributing guidelines
  • AI usage disclosure: Yes - Used claude to assist here - I've tested + reviewed every line and am prepared to discuss them.

@github-actions github-actions Bot added documentation Improvements or additions to documentation examples ggml changes relating to the ggml tensor library for machine learning labels Aug 1, 2026
@ryan5rdx
ryan5rdx marked this pull request as ready for review August 1, 2026 23:56
@ryan5rdx
ryan5rdx requested a review from a team as a code owner August 1, 2026 23:56
@ryan5rdx

ryan5rdx commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

benchmarks for Unsloth's Qwen 3.6 27B Q4_K_XL for something more practical:

cli:

./bin/llama-cli -m ~/Downloads/Qwen3.6-27B-MTP-UD-Q4_K_XL.gguf  -c 100000 --reasoning on -fa on --rpc <ip>:50052,...  -np 1 --jinja --reasoning-preserve -ub 512 -b 4096  --no-mmap  -ngl 999

workers:

./bin/ggml-rpc-server   --host 0.0.0.0 --port 50052 -d MTL0 -c  -t 12

TCP Baseline

Nodes Prefill t/s Decode t/s
1 245.2 24.4
2 221.4 18
3 206.7 17.3
4 196 17.7

Apple RDMA

Nodes Prefill t/s Decode t/s
1 245.2 24.4
2 237.5 22.5
3 232.2 20.5
4 227.8 19.8

Performance vs TCP

Nodes Prefill Decode
2 107.27% 125.00%
3 112.34% 118.50%
4 116.22% 111.86%

@ryan5rdx

ryan5rdx commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

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

Nodes Prefill t/s Decode t/s
1 408.93 27.6
2 290 22.37

TCP

Nodes Prefill t/s Decode t/s
1 408.93 27.6
2 275.1 14.7

Performance vs TCP

Nodes Prefill   Decode  
2 105.42% 152.18%

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.

@am17an

am17an commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@ryan5rdx can you try #26610?

@ryan5rdx ryan5rdx mentioned this pull request Aug 5, 2026
@ggerganov

Copy link
Copy Markdown
Member

@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

@ryan5rdx

ryan5rdx commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@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 rgerganov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread ggml/src/ggml-rpc/ggml-rpc.cpp Outdated
Comment thread ggml/src/ggml-rpc/ggml-rpc.cpp Outdated
@ryan5rdx
ryan5rdx force-pushed the ryan5rdx/apple-rdma-transport branch from c7b1b67 to 7cdd3fe Compare August 5, 2026 11:01
@ryan5rdx

ryan5rdx commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

@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.

@ryan5rdx
ryan5rdx requested a review from rgerganov August 5, 2026 11:17
@@ -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();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you try to measure the performance impact of having an explicit flush()? i.e. flushing on every send vs manual flushing like here

@ryan5rdx ryan5rdx Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread ggml/src/ggml-rpc/ggml-rpc.cpp Outdated
@ryan5rdx
ryan5rdx requested a review from rgerganov August 6, 2026 02:40

@rgerganov rgerganov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/**

@ryan5rdx
ryan5rdx requested a review from a team as a code owner August 6, 2026 15:32
@github-actions github-actions Bot added the devops improvements to build systems and github actions label Aug 6, 2026
@ryan5rdx
ryan5rdx requested a review from rgerganov August 6, 2026 15:44
@ryan5rdx

ryan5rdx commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

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):


Error: Service Unavailable
Error: Failed to resolve action download info.

@ryan5rdx

ryan5rdx commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@rgerganov let me know if there's anything I can do here!

@rgerganov rgerganov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@ryan5rdx

Copy link
Copy Markdown
Contributor Author

@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

@ryan5rdx

Copy link
Copy Markdown
Contributor Author

@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!

@rgerganov rgerganov added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Aug 25, 2026
@ggerganov

Copy link
Copy Markdown
Member

@ryan5rdx Could you rebase the branch on latest master?

@ryan5rdx
ryan5rdx force-pushed the ryan5rdx/apple-rdma-transport branch from a8e7767 to 0de310d Compare August 25, 2026 16:51
@ggerganov
ggerganov merged commit b114b47 into ggml-org:master Aug 25, 2026
29 of 31 checks passed
@srigi

srigi commented Aug 27, 2026

Copy link
Copy Markdown

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-devices

You pretty much locked all Sequoia users to the previous version without any future updates.

@ryan5rdx

Copy link
Copy Markdown
Contributor Author

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-devices

You pretty much locked all Sequoia users to the previous version without any future updates.

opps sorry - mind testing #27815 ?

@srigi

srigi commented Aug 27, 2026

Copy link
Copy Markdown

opps sorry - mind testing #27815 ?

Your branch compiled successfully and is working OK. Thank you.

2718 54 44

@ggerganov

Copy link
Copy Markdown
Member

@ryan5rdx Have you seen this error when running with RDMA:

image

@ryan5rdx

Copy link
Copy Markdown
Contributor Author

@ryan5rdx Have you seen this error when running with RDMA:
image

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

@ggerganov

Copy link
Copy Markdown
Member

On MacBook M5 Max 48GB:

./bin/ggml-rpc-server --host 0.0.0.0 --port 50052 -d MTL0 -c

On 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

@ryan5rdx

Copy link
Copy Markdown
Contributor Author

On MacBook M5 Max 48GB:

./bin/ggml-rpc-server --host 0.0.0.0 --port 50052 -d MTL0 -c

On 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.

ravel7524 pushed a commit to ravel7524/llama.cpp that referenced this pull request Aug 30, 2026
* 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>
@radekg

radekg commented Sep 3, 2026

Copy link
Copy Markdown

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

@cdvankammen

Copy link
Copy Markdown

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

devops improvements to build systems and github actions documentation Improvements or additions to documentation examples ggml changes relating to the ggml tensor library for machine learning merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants