char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
64a155d24
char/aliceai-t5-moe
1#include "ggml-rpc.h" 2#include "ggml-impl.h" 3#include "ggml-backend-impl.h" 4#include "ggml-cpp.h" 5#include "transport.h" 6 7#include <array> 8#include <cinttypes> 9#include <optional> 10#include <string> 11#include <vector> 12#include <queue> 13#include <condition_variable> 14#include <future> 15#include <memory> 16#include <mutex> 17#include <unordered_map> 18#include <unordered_set> 19#include <cstring> 20#include <fstream> 21#include <filesystem> 22#include <algorithm> 23#include <atomic> 24#include <thread> 25 26static const char * RPC_DEBUG = std::getenv ("GGML_RPC_DEBUG" ); 27 28#define LOG_DBG (...) \ 29 do { if (RPC_DEBUG) GGML_LOG_DEBUG(__VA_ARGS__); } while (0) 30 31 32namespace fs= std::filesystem; 33 34// macro for nicer error messages on server crash 35#define RPC_STATUS_ASSERT (x ) if (!(x)) GGML_ABORT("Remote RPC server crashed or returned malformed response") 36 37// all RPC structures must be packed 38#pragma pack(push, 1) 39// ggml_tensor is serialized into rpc_tensor 40struct rpc_tensor { 41uint64_t id ; 42uint32_t type ; 43uint64_t buffer ; 44uint32_t ne [GGML_MAX_DIMS ]; 45uint32_t nb [GGML_MAX_DIMS ]; 46uint32_t op ; 47int32_t op_params [GGML_MAX_OP_PARAMS /sizeof (int32_t )]; 48int32_t flags ; 49uint64_t src [GGML_MAX_SRC ]; 50uint64_t view_src ; 51uint64_t view_offs ; 52uint64_t data ; 53char name [GGML_MAX_NAME ]; 54 55int32_t use_count ; 56}; 57 58static_assert(sizeof (rpc_tensor ) %8 == 0 ,"rpc_tensor size must be multiple of 8" ); 59 60// RPC commands 61enum rpc_cmd { 62RPC_CMD_ALLOC_BUFFER = 0 , 63RPC_CMD_GET_ALIGNMENT , 64RPC_CMD_GET_MAX_SIZE , 65RPC_CMD_BUFFER_GET_BASE , 66RPC_CMD_FREE_BUFFER , 67RPC_CMD_BUFFER_CLEAR , 68RPC_CMD_SET_TENSOR , 69RPC_CMD_SET_TENSOR_HASH , 70RPC_CMD_GET_TENSOR , 71RPC_CMD_COPY_TENSOR , 72RPC_CMD_GRAPH_COMPUTE , 73RPC_CMD_GET_DEVICE_MEMORY , 74RPC_CMD_INIT_TENSOR , 75RPC_CMD_GET_ALLOC_SIZE , 76RPC_CMD_HELLO , 77RPC_CMD_DEVICE_COUNT , 78RPC_CMD_GRAPH_RECOMPUTE , 79RPC_CMD_MEMSET_TENSOR , 80RPC_CMD_NONE , 81RPC_CMD_COUNT , 82}; 83 84static_assert(RPC_CMD_HELLO == 14 ,"RPC_CMD_HELLO must be always 14" ); 85 86// Try RPC_CMD_SET_TENSOR_HASH first when data size is larger than this threshold 87const size_t HASH_THRESHOLD = 10 * 1024 * 1024 ; 88 89struct rpc_msg_hello_req { 90uint8_t conn_caps [RPC_CONN_CAPS_SIZE ]; 91}; 92 93struct rpc_msg_hello_rsp { 94uint8_t major ; 95uint8_t minor ; 96uint8_t patch ; 97uint8_t padding ; 98uint8_t conn_caps [RPC_CONN_CAPS_SIZE ]; 99}; 100 101struct rpc_msg_device_count_rsp { 102uint32_t device_count ; 103}; 104 105struct rpc_msg_get_alloc_size_req { 106uint32_t device ; 107rpc_tensor tensor ; 108rpc_tensor srcs [GGML_MAX_SRC ]; 109}; 110 111struct rpc_msg_get_alloc_size_rsp { 112uint64_t alloc_size ; 113}; 114 115struct rpc_msg_init_tensor_req { 116rpc_tensor tensor ; 117}; 118 119struct rpc_msg_alloc_buffer_req { 120uint32_t device ; 121uint64_t size ; 122}; 123 124struct rpc_msg_alloc_buffer_rsp { 125uint64_t remote_ptr ; 126uint64_t remote_size ; 127}; 128 129struct rpc_msg_get_alignment_req { 130uint32_t device ; 131}; 132 133struct rpc_msg_get_alignment_rsp { 134uint64_t alignment ; 135}; 136 137struct rpc_msg_get_max_size_req { 138uint32_t device ; 139}; 140 141struct rpc_msg_get_max_size_rsp { 142uint64_t max_size ; 143}; 144 145struct rpc_msg_buffer_get_base_req { 146uint64_t remote_ptr ; 147}; 148 149struct rpc_msg_buffer_get_base_rsp { 150uint64_t base_ptr ; 151}; 152 153struct rpc_msg_free_buffer_req { 154uint64_t remote_ptr ; 155}; 156 157struct rpc_msg_buffer_clear_req { 158uint64_t remote_ptr ; 159uint8_t value ; 160}; 161 162struct rpc_msg_memset_tensor_req { 163rpc_tensor tensor ; 164uint64_t offset ; 165uint64_t size ; 166uint8_t value ; 167}; 168 169struct rpc_msg_set_tensor_hash_req { 170rpc_tensor tensor ; 171uint64_t offset ; 172uint64_t hash ; 173}; 174 175struct rpc_msg_set_tensor_hash_rsp { 176uint8_t result ; 177}; 178 179struct rpc_msg_get_tensor_req { 180rpc_tensor tensor ; 181uint64_t offset ; 182uint64_t size ; 183}; 184 185struct rpc_msg_copy_tensor_req { 186rpc_tensor src ; 187rpc_tensor dst ; 188}; 189 190struct rpc_msg_copy_tensor_rsp { 191uint8_t result ; 192}; 193 194struct rpc_msg_get_device_memory_req { 195uint32_t device ; 196}; 197 198struct rpc_msg_get_device_memory_rsp { 199uint64_t free_mem ; 200uint64_t total_mem ; 201}; 202 203struct rpc_msg_graph_recompute_req { 204uint32_t device ; 205}; 206 207#pragma pack(pop) 208 209// RPC data structures 210 211static ggml_guid_t ggml_backend_rpc_guid () { 212static ggml_guid guid = {0x99 ,0x68 ,0x5b ,0x6c ,0xd2 ,0x83 ,0x3d ,0x24 ,0x25 ,0x36 ,0x72 ,0xe1 ,0x5b ,0x0e ,0x14 ,0x03 }; 213return & guid ; 214} 215 216struct ggml_backend_rpc_device_context { 217 std::string endpoint ; 218uint32_t device ; 219 std::string name ; 220 std::string description ; 221uint64_t last_graph_uid ; 222}; 223 224struct ggml_backend_rpc_buffer_type_context { 225 std::string endpoint ; 226uint32_t device ; 227 std::string name ; 228size_t alignment ; 229size_t max_size ; 230}; 231 232class rpc_dispatcher ; 233struct ggml_backend_rpc_context { 234 std::shared_ptr < rpc_dispatcher > dispatcher ; 235uint32_t device ; 236 std::string name ; 237}; 238 239struct ggml_backend_rpc_buffer_context { 240 std::shared_ptr < rpc_dispatcher > dispatcher ; 241void * base_ptr ; 242uint64_t remote_ptr ; 243}; 244 245// RPC helper functions 246 247// Computes FNV-1a hash of the data 248static uint64_t fnv_hash (const uint8_t * data ,size_t len ,uint64_t hash = 0xcbf29ce484222325ULL ) { 249const uint64_t fnv_prime = 0x100000001b3ULL ; 250 251for (size_t i = 0 ;i < len ;++ i ) { 252hash ^=data [i ]; 253hash *=fnv_prime ; 254 } 255return hash ; 256} 257 258static bool send_msg (socket_ptr sock ,const void * msg ,size_t msg_size ) { 259if (!sock -> send_data (& msg_size ,sizeof (msg_size ))) { 260return false; 261 } 262if (!sock -> send_data (msg ,msg_size )) { 263return false; 264 } 265return sock -> flush (); 266} 267 268static bool recv_msg (socket_ptr sock ,void * msg ,size_t msg_size ) { 269uint64_t size ; 270if (!sock -> recv_data (& size ,sizeof (size ))) { 271return false; 272 } 273if (size != msg_size ) { 274return false; 275 } 276return sock -> recv_data (msg ,msg_size ); 277} 278 279static bool recv_msg (socket_ptr sock , std::vector < uint8_t > & input ) { 280uint64_t size ; 281if (!sock -> recv_data (& size ,sizeof (size ))) { 282return false; 283 } 284try { 285input .resize (size ); 286 }catch (const std::bad_alloc & e ) { 287GGML_LOG_ERROR ("Failed to allocate input buffer of size %" PRIu64 "\n" ,size ); 288return false; 289 } 290return sock -> recv_data (input .data (),size ); 291} 292 293static bool parse_endpoint (const std::string & endpoint , std::string & host ,int & port ) { 294size_t pos = endpoint .find (':' ); 295if (pos == std::string::npos ) { 296return false; 297 } 298host = endpoint .substr (0 ,pos ); 299try { 300port = std::stoi (endpoint .substr (pos + 1 )); 301 }catch (...) { 302return false; 303 } 304return true; 305} 306 307// RPC request : | rpc_cmd (1 byte) | request_size (8 bytes) | request_data (request_size bytes) | 308// No response 309static bool send_rpc_cmd (socket_ptr sock ,enum rpc_cmd cmd ,const void * input ,size_t input_size ) { 310uint8_t cmd_byte = cmd ; 311if (!sock -> send_data (& cmd_byte ,sizeof (cmd_byte ))) { 312return false; 313 } 314if (!sock -> send_data (& input_size ,sizeof (input_size ))) { 315return false; 316 } 317if (!sock -> send_data (input ,input_size )) { 318return false; 319 } 320return sock -> flush (); 321} 322 323// RPC request : | rpc_cmd (1 byte) | request_size (8 bytes) | request_data (request_size bytes) | 324// RPC response: | response_size (8 bytes) | response_data (response_size bytes) | 325static bool send_rpc_cmd (socket_ptr sock ,enum rpc_cmd cmd ,const void * input ,size_t input_size ,void * output ,size_t output_size ) { 326if (!send_rpc_cmd (sock ,cmd ,input ,input_size )) { 327return false; 328 } 329uint64_t out_size ; 330if (!sock -> recv_data (& out_size ,sizeof (out_size ))) { 331return false; 332 } 333if (out_size != output_size ) { 334return false; 335 } 336if (!sock -> recv_data (output ,output_size )) { 337return false; 338 } 339return true; 340} 341 342// RPC client-side implementation 343 344// Performs HELLO handshake with transport auto-negotiation. 345// Advertises local capabilities via conn_caps; if the server responds with 346// matching capabilities, the socket is upgraded transparently. 347static bool negotiate_hello (const std::shared_ptr < socket_t > & sock ) { 348rpc_msg_hello_req request = {}; 349rpc_msg_hello_rsp response = {}; 350 351sock -> get_caps (request .conn_caps ); 352 353bool status = send_rpc_cmd (sock ,RPC_CMD_HELLO ,& request ,sizeof (request ),& response ,sizeof (response )); 354RPC_STATUS_ASSERT (status ); 355 356if (response .major != RPC_PROTO_MAJOR_VERSION || response .minor > RPC_PROTO_MINOR_VERSION ) { 357GGML_LOG_ERROR ("RPC server version mismatch: %d.%d.%d\n" , 358response .major ,response .minor ,response .patch ); 359return false; 360 } 361 362sock -> update_caps (response .conn_caps ); 363return true; 364} 365 366template < typename T > 367class message_queue { 368public : 369message_queue () {} 370 371bool push (const T & value ) { 372 std::unique_lock < std::mutex > lock (mutex ); 373if (interrupted ) { 374return false; 375 } 376queue .push (value ); 377cvar .notify_all (); 378return true; 379 } 380 381bool pop (T * out ) { 382 std::unique_lock < std::mutex > lock (mutex ); 383cvar .wait (lock , [this ] {return !queue .empty ()|| interrupted ; }); 384if (interrupted ) { 385return false; 386 } 387* out = queue .front (); 388queue .pop (); 389return true; 390 } 391 392void interrupt () { 393 std::unique_lock < std::mutex > lock (mutex ); 394interrupted = true; 395lock .unlock (); 396cvar .notify_all (); 397 } 398 399private : 400bool interrupted = false; 401 std::queue < T > queue ; 402 std::mutex mutex ; 403 std::condition_variable cvar ; 404}; 405 406class rpc_dispatcher { 407public : 408rpc_dispatcher () { 409 } 410 411void send (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ); 412void send (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ,void * output ,size_t output_size ); 413void send_async (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ); 414void send_async (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ,void * output ,size_t output_size ); 415 416ggml_backend_event_t event_new (ggml_backend_dev_t dev ); 417void event_free (ggml_backend_event_t event ); 418void event_synchronize (ggml_backend_event_t event ); 419void event_record (ggml_backend_event_t event ); 420void synchronize (); 421 422void start (const std::string & endpoint ); 423void work (); 424 425 ~rpc_dispatcher (); 426 427private : 428struct rpc_msg { 429rpc_cmd cmd ; 430 std::shared_ptr < const void > input ; 431size_t input_size ; 432void * output ; 433size_t output_size ; 434 std::promise < void > completion ; 435 }; 436using rpc_msg_ptr = std::shared_ptr < rpc_msg > ; 437using rpc_msg_queue = message_queue < rpc_msg_ptr > ; 438struct rpc_event { 439rpc_msg_ptr msg ; 440 std::shared_future < void > sf ; 441 }; 442rpc_msg_queue queue ; 443socket_ptr sock ; 444 std::atomic_bool running ; 445 std::thread thread ; 446}; 447 448static void rpc_dispatcher_trampoline (rpc_dispatcher * dispatcher ) 449{ 450dispatcher -> work (); 451} 452 453void rpc_dispatcher::send (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ) { 454auto msg = std::make_shared < rpc_msg > (); 455msg -> cmd = cmd ; 456msg -> input = input ; 457msg -> input_size = input_size ; 458msg -> output = nullptr ; 459msg -> output_size = 0 ; 460GGML_ASSERT (queue .push (msg )); 461auto future = msg -> completion .get_future (); 462future .wait (); 463} 464 465void rpc_dispatcher::send_async (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ) { 466auto msg = std::make_shared < rpc_msg > (); 467msg -> cmd = cmd ; 468msg -> input = input ; 469msg -> input_size = input_size ; 470msg -> output = nullptr ; 471msg -> output_size = 0 ; 472GGML_ASSERT (queue .push (msg )); 473} 474 475void rpc_dispatcher::send (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ,void * output ,size_t output_size ) { 476auto msg = std::make_shared < rpc_msg > (); 477msg -> cmd = cmd ; 478msg -> input = input ; 479msg -> input_size = input_size ; 480msg -> output = output ; 481msg -> output_size = output_size ; 482GGML_ASSERT (queue .push (msg )); 483auto future = msg -> completion .get_future (); 484future .wait (); 485} 486 487void rpc_dispatcher::send_async (enum rpc_cmd cmd , std::shared_ptr < const void > input ,size_t input_size ,void * output ,size_t output_size ) { 488auto msg = std::make_shared < rpc_msg > (); 489msg -> cmd = cmd ; 490msg -> input = input ; 491msg -> input_size = input_size ; 492msg -> output = output ; 493msg -> output_size = output_size ; 494GGML_ASSERT (queue .push (msg )); 495} 496 497ggml_backend_event_t rpc_dispatcher::event_new (ggml_backend_dev_t dev ) { 498rpc_event * ev = new rpc_event ; 499ev -> msg = std::make_shared < rpc_msg > (); 500ev -> msg -> cmd = RPC_CMD_NONE ; 501ev -> sf = ev -> msg -> completion .get_future ().share (); 502GGML_ASSERT (queue .push (ev -> msg )); 503return new ggml_backend_event { 504/* .device = */ dev , 505/* .context = */ ev , 506 }; 507} 508 509void rpc_dispatcher::event_free (ggml_backend_event_t event ) { 510rpc_event * ev = (rpc_event * )event -> context ; 511delete ev ; 512} 513 514void rpc_dispatcher::event_synchronize (ggml_backend_event_t event ) { 515rpc_event * ev = (rpc_event * )event -> context ; 516ev -> sf .wait (); 517} 518 519void rpc_dispatcher::event_record (ggml_backend_event_t event ) { 520rpc_event * ev = (rpc_event * )event -> context ; 521ev -> msg = std::make_shared < rpc_msg > (); 522ev -> msg -> cmd = RPC_CMD_NONE ; 523ev -> sf = ev -> msg -> completion .get_future ().share (); 524GGML_ASSERT (queue .push (ev -> msg )); 525} 526 527void rpc_dispatcher::synchronize () { 528// to ensure all messages are processed, submit dummy message and wait for it to complete 529auto msg = std::make_shared < rpc_msg > (); 530msg -> cmd = RPC_CMD_NONE ; 531GGML_ASSERT (queue .push (msg )); 532msg -> completion .get_future ().wait (); 533} 534 535void rpc_dispatcher::start (const std::string & endpoint ) { 536 std::string host ; 537int port ; 538if (!parse_endpoint (endpoint ,host ,port )) { 539GGML_ABORT ("Failed to parse endpoint: %s\n" ,endpoint .c_str ()); 540 } 541if (!rpc_transport_init ()) { 542GGML_ABORT ("RPC transport initialization failed\n" ); 543 } 544 545sock = socket_t::connect (host .c_str (),port ); 546if (sock == nullptr ) { 547GGML_ABORT ("Failed to connect to %s\n" ,endpoint .c_str ()); 548 } 549if (!negotiate_hello (sock )) { 550GGML_ABORT ("RPC handshake failed for %s\n" ,endpoint .c_str ()); 551 } 552LOG_DBG ("[%s] connected to %s\n" ,__func__ ,endpoint .c_str ()); 553running = true; 554thread = std::thread (rpc_dispatcher_trampoline ,this ); 555} 556 557void rpc_dispatcher::work () { 558while (running ) { 559rpc_msg_ptr msg_ptr ; 560if (!queue .pop (& msg_ptr )) { 561break ; 562 } 563if (msg_ptr -> cmd != RPC_CMD_NONE ) { 564if (msg_ptr -> output ) { 565bool status = send_rpc_cmd (sock ,msg_ptr -> cmd ,msg_ptr -> input .get (),msg_ptr -> input_size ,msg_ptr -> output ,msg_ptr -> output_size ); 566RPC_STATUS_ASSERT (status ); 567 }else { 568bool status = send_rpc_cmd (sock ,msg_ptr -> cmd ,msg_ptr -> input .get (),msg_ptr -> input_size ); 569RPC_STATUS_ASSERT (status ); 570 } 571 } 572msg_ptr -> completion .set_value (); 573 } 574} 575 576rpc_dispatcher::~rpc_dispatcher () { 577running = false; 578queue .interrupt (); 579sock = nullptr ; 580if (thread .joinable ()) { 581thread .join (); 582 } 583} 584 585static std::shared_ptr < rpc_dispatcher > get_dispatcher (const std::string & endpoint ) { 586static std::mutex mutex ; 587 std::lock_guard < std::mutex > lock (mutex ); 588static std::unordered_map < std::string , std::weak_ptr < rpc_dispatcher >> dispatchers ; 589 590auto it = dispatchers .find (endpoint ); 591if (it != dispatchers .end ()) { 592if (auto dispatcher = it -> second .lock ()) { 593return dispatcher ; 594 } 595 } 596 597auto dispatcher = std::make_shared < rpc_dispatcher > (); 598dispatcher -> start (endpoint ); 599dispatchers [endpoint ]= dispatcher ; 600return dispatcher ; 601} 602 603static void ggml_backend_rpc_buffer_free_buffer (ggml_backend_buffer_t buffer ) { 604ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 605auto request = std::make_shared < rpc_msg_free_buffer_req > (); 606request -> remote_ptr = ctx -> remote_ptr ; 607ctx -> dispatcher -> send (RPC_CMD_FREE_BUFFER ,request ,sizeof (* request )); 608delete ctx ; 609} 610 611static void * ggml_backend_rpc_buffer_get_base (ggml_backend_buffer_t buffer ) { 612ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 613if (ctx -> base_ptr != nullptr ) { 614return ctx -> base_ptr ; 615 } 616auto request = std::make_shared < rpc_msg_buffer_get_base_req > (); 617request -> remote_ptr = ctx -> remote_ptr ; 618rpc_msg_buffer_get_base_rsp response ; 619ctx -> dispatcher -> send (RPC_CMD_BUFFER_GET_BASE ,request ,sizeof (* request ),& response ,sizeof (response )); 620ctx -> base_ptr = reinterpret_cast < void *> (response .base_ptr ); 621return ctx -> base_ptr ; 622} 623 624static bool ggml_backend_buffer_is_rpc (ggml_backend_buffer_t buffer ) { 625return buffer -> iface .free_buffer == ggml_backend_rpc_buffer_free_buffer ; 626} 627 628static rpc_tensor serialize_tensor (const ggml_tensor * tensor ,const std::shared_ptr < rpc_dispatcher > & dispatcher = nullptr ) { 629rpc_tensor result ; 630if (!tensor ) { 631memset (& result ,0 ,sizeof (result )); 632return result ; 633 } 634 635result .id = reinterpret_cast < uint64_t > (tensor ); 636result .type = tensor -> type ; 637if (tensor -> buffer && ggml_backend_buffer_is_rpc (tensor -> buffer )) { 638ggml_backend_buffer_t buffer = tensor -> buffer ; 639ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 640// ref: https://github.com/ggml-org/llama.cpp/pull/26500 641if (ctx != nullptr && (dispatcher == nullptr || ctx -> dispatcher == dispatcher )) { 642result .buffer = ctx -> remote_ptr ; 643result .data = reinterpret_cast < uint64_t > (tensor -> data ); 644 }else { 645result .buffer = 0 ; 646result .data = 0 ; 647 } 648 }else { 649result .buffer = 0 ; 650result .data = 0 ; 651 } 652for (uint32_t i = 0 ;i < GGML_MAX_DIMS ;i ++ ) { 653result .ne [i ]= tensor -> ne [i ]; 654result .nb [i ]= tensor -> nb [i ]; 655 } 656result .op = tensor -> op ; 657for (uint32_t i = 0 ;i < GGML_MAX_OP_PARAMS /sizeof (int32_t );i ++ ) { 658result .op_params [i ]= tensor -> op_params [i ]; 659 } 660result .flags = tensor -> flags ; 661for (uint32_t i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 662result .src [i ]= reinterpret_cast < uint64_t > (tensor -> src [i ]); 663 } 664result .view_src = reinterpret_cast < uint64_t > (tensor -> view_src ); 665result .view_offs = tensor -> view_offs ; 666 667// Avoid sending uninitialized data over the wire 668memset (result .name ,0 ,sizeof (result .name )); 669result .use_count = 0 ; 670 671snprintf (result .name ,GGML_MAX_NAME ,"%s" ,tensor -> name ); 672return result ; 673} 674 675static enum ggml_status ggml_backend_rpc_buffer_init_tensor (ggml_backend_buffer_t buffer ,ggml_tensor * tensor ) { 676ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 677 678// CUDA backend on the server pads everything to 512 due to CUDA limitations. 679// Due to bandwidth constraints, we only call the server init tensor functions if necessary. 680// In particular, only quantized tensors need padding 681if (ggml_is_quantized (tensor -> type )&& (tensor -> ne [0 ] %512 != 0 )&& (tensor -> view_src == nullptr )) { 682auto request = std::make_shared < rpc_msg_init_tensor_req > (); 683request -> tensor = serialize_tensor (tensor ); 684ctx -> dispatcher -> send (RPC_CMD_INIT_TENSOR ,request ,sizeof (* request )); 685 } 686return GGML_STATUS_SUCCESS ; 687} 688 689static void ggml_backend_rpc_buffer_memset_tensor ( 690ggml_backend_buffer_t buffer ,ggml_tensor * tensor ,uint8_t value ,size_t offset ,size_t size ) { 691ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 692auto request = std::make_shared < rpc_msg_memset_tensor_req > (); 693request -> tensor = serialize_tensor (tensor ); 694request -> offset = offset ; 695request -> size = size ; 696request -> value = value ; 697ctx -> dispatcher -> send (RPC_CMD_MEMSET_TENSOR ,request ,sizeof (* request )); 698} 699 700static void ggml_backend_rpc_buffer_set_tensor (ggml_backend_buffer_t buffer ,ggml_tensor * tensor ,const void * data ,size_t offset ,size_t size ) { 701ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 702rpc_tensor rpc_tensor = serialize_tensor (tensor ); 703if (size > HASH_THRESHOLD ) { 704auto request = std::make_shared < rpc_msg_set_tensor_hash_req > (); 705request -> tensor = rpc_tensor ; 706request -> offset = offset ; 707request -> hash = fnv_hash ((const uint8_t * )data ,size ); 708rpc_msg_set_tensor_hash_rsp response ; 709ctx -> dispatcher -> send (RPC_CMD_SET_TENSOR_HASH ,request ,sizeof (* request ),& response ,sizeof (response )); 710if (response .result ) { 711// the server has the same data, no need to send it 712return ; 713 } 714 } 715// input serialization format: | rpc_tensor | offset (8 bytes) | data (size bytes) 716size_t input_size = sizeof (rpc_tensor )+ sizeof (uint64_t )+ size ; 717uint8_t * input = new uint8_t [input_size ](); 718memcpy (input ,& rpc_tensor ,sizeof (rpc_tensor )); 719memcpy (input + sizeof (rpc_tensor ),& offset ,sizeof (offset )); 720memcpy (input + sizeof (rpc_tensor )+ sizeof (offset ),data ,size ); 721 std::shared_ptr < uint8_t > input_ptr (input , std::default_delete < uint8_t []> ()); 722ctx -> dispatcher -> send (RPC_CMD_SET_TENSOR ,input_ptr ,input_size ); 723} 724 725static void ggml_backend_rpc_buffer_get_tensor (ggml_backend_buffer_t buffer ,const ggml_tensor * tensor ,void * data ,size_t offset ,size_t size ) { 726ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 727auto request = std::make_shared < rpc_msg_get_tensor_req > (); 728request -> tensor = serialize_tensor (tensor ); 729request -> offset = offset ; 730request -> size = size ; 731ctx -> dispatcher -> send (RPC_CMD_GET_TENSOR ,request ,sizeof (* request ),data ,size ); 732} 733 734static bool ggml_backend_rpc_buffer_cpy_tensor (ggml_backend_buffer_t buffer ,const ggml_tensor * src ,ggml_tensor * dst ) { 735if (ggml_backend_buffer_is_rpc (src -> buffer )) { 736// check if src and dst are on the same server 737ggml_backend_buffer_t src_buffer = src -> buffer ; 738ggml_backend_rpc_buffer_context * src_ctx = (ggml_backend_rpc_buffer_context * )src_buffer -> context ; 739ggml_backend_buffer_t dst_buffer = dst -> buffer ; 740ggml_backend_rpc_buffer_context * dst_ctx = (ggml_backend_rpc_buffer_context * )dst_buffer -> context ; 741if (src_ctx -> dispatcher != dst_ctx -> dispatcher ) { 742return false; 743 } 744ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 745auto request = std::make_shared < rpc_msg_copy_tensor_req > (); 746request -> src = serialize_tensor (src ); 747request -> dst = serialize_tensor (dst ); 748rpc_msg_copy_tensor_rsp response ; 749ctx -> dispatcher -> send (RPC_CMD_COPY_TENSOR ,request ,sizeof (* request ),& response ,sizeof (response )); 750return response .result ; 751 } 752return false; 753} 754 755static void ggml_backend_rpc_buffer_clear (ggml_backend_buffer_t buffer ,uint8_t value ) { 756ggml_backend_rpc_buffer_context * ctx = (ggml_backend_rpc_buffer_context * )buffer -> context ; 757auto request = std::make_shared < rpc_msg_buffer_clear_req > (); 758request -> remote_ptr = ctx -> remote_ptr ; 759request -> value = value ; 760ctx -> dispatcher -> send (RPC_CMD_BUFFER_CLEAR ,request ,sizeof (* request )); 761} 762 763static ggml_backend_buffer_i ggml_backend_rpc_buffer_interface = { 764/* .free_buffer = */ ggml_backend_rpc_buffer_free_buffer , 765/* .get_base = */ ggml_backend_rpc_buffer_get_base , 766/* .init_tensor = */ ggml_backend_rpc_buffer_init_tensor , 767/* .memset_tensor = */ ggml_backend_rpc_buffer_memset_tensor , 768/* .set_tensor = */ ggml_backend_rpc_buffer_set_tensor , 769/* .get_tensor = */ ggml_backend_rpc_buffer_get_tensor , 770/* .set_tensor_2d = */ NULL , 771/* .get_tensor_2d = */ NULL , 772/* .cpy_tensor = */ ggml_backend_rpc_buffer_cpy_tensor , 773/* .clear = */ ggml_backend_rpc_buffer_clear , 774/* .reset = */ NULL , 775}; 776 777static const char * ggml_backend_rpc_buffer_type_name (ggml_backend_buffer_type_t buft ) { 778ggml_backend_rpc_buffer_type_context * buft_ctx = (ggml_backend_rpc_buffer_type_context * )buft -> context ; 779return buft_ctx -> name .c_str (); 780} 781 782static ggml_backend_buffer_t ggml_backend_rpc_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft ,size_t size ) { 783ggml_backend_rpc_buffer_type_context * buft_ctx = (ggml_backend_rpc_buffer_type_context * )buft -> context ; 784auto request = std::make_shared < rpc_msg_alloc_buffer_req > (); 785request -> device = buft_ctx -> device ; 786request -> size = size ; 787rpc_msg_alloc_buffer_rsp response ; 788 789auto dispatcher = get_dispatcher (buft_ctx -> endpoint ); 790dispatcher -> send (RPC_CMD_ALLOC_BUFFER ,request ,sizeof (* request ),& response ,sizeof (response )); 791if (response .remote_ptr != 0 ) { 792ggml_backend_buffer_t buffer = ggml_backend_buffer_init (buft , 793ggml_backend_rpc_buffer_interface , 794new ggml_backend_rpc_buffer_context {dispatcher ,nullptr ,response .remote_ptr }, 795response .remote_size ); 796return buffer ; 797 }else { 798return nullptr ; 799 } 800} 801 802static size_t get_alignment (const std::shared_ptr < rpc_dispatcher > & dispatcher ,uint32_t device ) { 803auto request = std::make_shared < rpc_msg_get_alignment_req > (); 804request -> device = device ; 805rpc_msg_get_alignment_rsp response ; 806dispatcher -> send (RPC_CMD_GET_ALIGNMENT ,request ,sizeof (* request ),& response ,sizeof (response )); 807return response .alignment ; 808} 809 810static size_t ggml_backend_rpc_buffer_type_get_alignment (ggml_backend_buffer_type_t buft ) { 811ggml_backend_rpc_buffer_type_context * buft_ctx = (ggml_backend_rpc_buffer_type_context * )buft -> context ; 812return buft_ctx -> alignment ; 813} 814 815static size_t get_max_size (const std::shared_ptr < rpc_dispatcher > & dispatcher ,uint32_t device ) { 816auto request = std::make_shared < rpc_msg_get_max_size_req > (); 817request -> device = device ; 818rpc_msg_get_max_size_rsp response ; 819dispatcher -> send (RPC_CMD_GET_MAX_SIZE ,request ,sizeof (* request ),& response ,sizeof (response )); 820return response .max_size ; 821} 822 823static size_t ggml_backend_rpc_get_max_size (ggml_backend_buffer_type_t buft ) { 824ggml_backend_rpc_buffer_type_context * buft_ctx = (ggml_backend_rpc_buffer_type_context * )buft -> context ; 825return buft_ctx -> max_size ; 826} 827 828static size_t ggml_backend_rpc_buffer_type_get_alloc_size (ggml_backend_buffer_type_t buft ,const ggml_tensor * tensor ) { 829// should we query the remote server for the actual size 830bool rpc_get = false; 831 832// See comments in init_tensor. 833rpc_get |=ggml_is_quantized (tensor -> type )&& (tensor -> ne [0 ] %512 != 0 )&& (tensor -> view_src == nullptr ); 834 835// [TAG_ALLOC_SIZE_EXPAND] 836// ops that may require additional memory for fleeting data on certain backends 837// ref: https://github.com/ggml-org/llama.cpp/pull/15966 838rpc_get |=ggml_op_alloc_size_may_expand (tensor -> op ); 839 840if (rpc_get ) { 841ggml_backend_rpc_buffer_type_context * buft_ctx = (ggml_backend_rpc_buffer_type_context * )buft -> context ; 842 843// Cache key for calls to read the alloc_size. 844// We deliberately exclude src tensor dimensions from the key because: 845// 1. For CPU backends, alloc_size = ggml_nbytes(output) regardless of src shapes 846// 2. For GPU backends, the reservation graph uses max dimensions, so the 847// cached value from reservation is always >= any subsequent request 848// 3. Including src dims causes cache misses per-ubatch (e.g. growing KV cache) 849// which blocks the main thread behind in-flight GRAPH_COMPUTE commands 850struct alloc_size_cache_key { 851uint32_t device ; 852uint32_t type ; 853uint32_t op ; 854int32_t op_params [GGML_MAX_OP_PARAMS /sizeof (int32_t )]; 855uint32_t ne [GGML_MAX_DIMS ]; 856 }; 857 858alloc_size_cache_key key = {}; 859key .device = buft_ctx -> device ; 860key .type = tensor -> type ; 861key .op = tensor -> op ; 862memcpy (key .op_params ,tensor -> op_params ,sizeof (key .op_params )); 863for (int i = 0 ;i < GGML_MAX_DIMS ;i ++ ) { 864key .ne [i ]= (uint32_t )tensor -> ne [i ]; 865 } 866 867uint64_t cache_hash = fnv_hash ((const uint8_t * )& key ,sizeof (key )); 868cache_hash = fnv_hash ((const uint8_t * )buft_ctx -> endpoint .data (),buft_ctx -> endpoint .size (),cache_hash ); 869 870// alloc sizes are immutable for a given tensor configuration 871static std::mutex cache_mutex ; 872static std::unordered_map < uint64_t ,size_t > cache ; 873 874 { 875 std::lock_guard < std::mutex > lock (cache_mutex ); 876auto it = cache .find (cache_hash ); 877if (it != cache .end ()) { 878return it -> second ; 879 } 880 } 881 882auto request = std::make_shared < rpc_msg_get_alloc_size_req > (); 883request -> device = buft_ctx -> device ; 884request -> tensor = serialize_tensor (tensor ); 885 886// .get_alloc_size could be a function of the tensor's srcs, so we must serialize them as well 887for (int i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 888request -> srcs [i ]= serialize_tensor (tensor -> src [i ]); 889 } 890 891rpc_msg_get_alloc_size_rsp response ; 892auto dispatcher = get_dispatcher (buft_ctx -> endpoint ); 893dispatcher -> send (RPC_CMD_GET_ALLOC_SIZE ,request ,sizeof (* request ),& response ,sizeof (response )); 894 895 { 896 std::lock_guard < std::mutex > lock (cache_mutex ); 897cache [cache_hash ]= response .alloc_size ; 898 } 899 900return response .alloc_size ; 901 } 902 903return ggml_nbytes (tensor ); 904} 905 906static ggml_backend_buffer_type_i ggml_backend_rpc_buffer_type_interface = { 907/* .get_name = */ ggml_backend_rpc_buffer_type_name , 908/* .alloc_buffer = */ ggml_backend_rpc_buffer_type_alloc_buffer , 909/* .get_alignment = */ ggml_backend_rpc_buffer_type_get_alignment , 910/* .get_max_size = */ ggml_backend_rpc_get_max_size , 911/* .get_alloc_size = */ ggml_backend_rpc_buffer_type_get_alloc_size , 912/* .is_host = */ NULL , 913}; 914 915static const char * ggml_backend_rpc_name (ggml_backend_t backend ) { 916ggml_backend_rpc_context * rpc_ctx = (ggml_backend_rpc_context * )backend -> context ; 917 918return rpc_ctx -> name .c_str (); 919} 920 921static void ggml_backend_rpc_free (ggml_backend_t backend ) { 922ggml_backend_rpc_context * rpc_ctx = (ggml_backend_rpc_context * )backend -> context ; 923delete rpc_ctx ; 924delete backend ; 925} 926 927static void ggml_backend_rpc_set_tensor_async (ggml_backend_t backend ,ggml_tensor * tensor ,const void * data ,size_t offset ,size_t size ) { 928ggml_backend_rpc_context * ctx = (ggml_backend_rpc_context * )backend -> context ; 929rpc_tensor rpc_tensor = serialize_tensor (tensor ); 930if (size > HASH_THRESHOLD ) { 931auto request = std::make_shared < rpc_msg_set_tensor_hash_req > (); 932request -> tensor = rpc_tensor ; 933request -> offset = offset ; 934request -> hash = fnv_hash ((const uint8_t * )data ,size ); 935rpc_msg_set_tensor_hash_rsp response ; 936// TODO: make this async 937ctx -> dispatcher -> send (RPC_CMD_SET_TENSOR_HASH ,request ,sizeof (* request ),& response ,sizeof (response )); 938if (response .result ) { 939// the server has the same data, no need to send it 940return ; 941 } 942 } 943// input serialization format: | rpc_tensor | offset (8 bytes) | data (size bytes) 944size_t input_size = sizeof (rpc_tensor )+ sizeof (uint64_t )+ size ; 945uint8_t * input = new uint8_t [input_size ](); 946memcpy (input ,& rpc_tensor ,sizeof (rpc_tensor )); 947memcpy (input + sizeof (rpc_tensor ),& offset ,sizeof (offset )); 948memcpy (input + sizeof (rpc_tensor )+ sizeof (offset ),data ,size ); 949 std::shared_ptr < uint8_t > input_ptr (input , std::default_delete < uint8_t []> ()); 950ctx -> dispatcher -> send_async (RPC_CMD_SET_TENSOR ,input_ptr ,input_size ); 951} 952 953static void ggml_backend_rpc_get_tensor_async (ggml_backend_t backend ,const ggml_tensor * tensor ,void * data ,size_t offset ,size_t size ) { 954ggml_backend_rpc_context * ctx = (ggml_backend_rpc_context * )backend -> context ; 955auto request = std::make_shared < rpc_msg_get_tensor_req > (); 956request -> tensor = serialize_tensor (tensor ); 957request -> offset = offset ; 958request -> size = size ; 959ctx -> dispatcher -> send_async (RPC_CMD_GET_TENSOR ,request ,sizeof (* request ),data ,size ); 960} 961 962static void ggml_backend_rpc_synchronize (ggml_backend_t backend ) { 963ggml_backend_rpc_context * rpc_ctx = (ggml_backend_rpc_context * )backend -> context ; 964rpc_ctx -> dispatcher -> synchronize (); 965} 966 967static void add_tensor (ggml_tensor * tensor ,const ggml_cgraph * cgraph ,const std::shared_ptr < rpc_dispatcher > & dispatcher , std::vector < rpc_tensor > & tensors , std::unordered_set < ggml_tensor *> & visited ) { 968if (tensor == nullptr ) { 969return ; 970 } 971if (visited .find (tensor )!= visited .end ()) { 972return ; 973 } 974visited .insert (tensor ); 975for (int i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 976add_tensor (tensor -> src [i ],cgraph ,dispatcher ,tensors ,visited ); 977 } 978add_tensor (tensor -> view_src ,cgraph ,dispatcher ,tensors ,visited ); 979rpc_tensor result = serialize_tensor (tensor ,dispatcher ); 980const size_t hash_pos = ggml_hash_find (& cgraph -> visited_hash_set ,tensor ); 981if (hash_pos != GGML_HASHSET_FULL && ggml_bitset_get (cgraph -> visited_hash_set .used ,hash_pos )) { 982result .use_count = cgraph -> use_counts [hash_pos ]; 983 } 984tensors .push_back (result ); 985} 986 987static uint8_t * serialize_graph (uint32_t device ,const ggml_cgraph * cgraph ,const std::shared_ptr < rpc_dispatcher > & dispatcher ,size_t * output_size ) { 988uint32_t n_nodes = cgraph -> n_nodes ; 989 std::vector < rpc_tensor > tensors ; 990 std::unordered_set < ggml_tensor *> visited ; 991for (uint32_t i = 0 ;i < n_nodes ;i ++ ) { 992add_tensor (cgraph -> nodes [i ],cgraph ,dispatcher ,tensors ,visited ); 993 } 994// serialization format: 995// | device (4 bytes) | n_nodes (4 bytes) | nodes (n_nodes * sizeof(uint64_t) | n_tensors (4 bytes) | tensors (n_tensors * sizeof(rpc_tensor)) | 996uint32_t n_tensors = tensors .size (); 997* output_size = 2 * sizeof (uint32_t )+ n_nodes * sizeof (uint64_t )+ sizeof (uint32_t )+ n_tensors * sizeof (rpc_tensor ); 998uint8_t * output = new uint8_t [* output_size ](); 999uint8_t * dest = output ; 1000memcpy (dest ,& device ,sizeof (device )); 1001dest += sizeof (device ); 1002memcpy (dest ,& n_nodes ,sizeof (n_nodes )); 1003dest += sizeof (n_nodes ); 1004for (uint32_t i = 0 ;i < n_nodes ;i ++ ) { 1005memcpy (dest + i * sizeof (uint64_t ),& cgraph -> nodes [i ],sizeof (uint64_t )); 1006 } 1007dest += n_nodes * sizeof (uint64_t ); 1008memcpy (dest ,& n_tensors ,sizeof (n_tensors )); 1009dest += sizeof (n_tensors ); 1010rpc_tensor * out_tensors = (rpc_tensor * )dest ; 1011memcpy (out_tensors ,tensors .data (),n_tensors * sizeof (rpc_tensor )); 1012return output ; 1013} 1014 1015static enum ggml_status ggml_backend_rpc_graph_compute (ggml_backend_t backend ,ggml_cgraph * cgraph ) { 1016ggml_backend_rpc_context * rpc_ctx = (ggml_backend_rpc_context * )backend -> context ; 1017ggml_backend_dev_t rpc_dev = ggml_backend_get_device (backend ); 1018ggml_backend_rpc_device_context * rpc_dev_ctx = (ggml_backend_rpc_device_context * )rpc_dev -> context ; 1019 1020GGML_ASSERT (cgraph -> n_nodes > 0 ); 1021bool reuse = cgraph -> uid != 0 && rpc_dev_ctx -> last_graph_uid == cgraph -> uid ; 1022if (reuse ) { 1023auto request = std::make_shared < rpc_msg_graph_recompute_req > (); 1024request -> device = rpc_ctx -> device ; 1025rpc_ctx -> dispatcher -> send_async (RPC_CMD_GRAPH_RECOMPUTE ,request ,sizeof (* request )); 1026 }else { 1027rpc_dev_ctx -> last_graph_uid = cgraph -> uid ; 1028size_t input_size = 0 ; 1029uint8_t * input = serialize_graph (rpc_ctx -> device ,cgraph ,rpc_ctx -> dispatcher ,& input_size ); 1030 std::shared_ptr < uint8_t > input_ptr (input , std::default_delete < uint8_t []> ()); 1031rpc_ctx -> dispatcher -> send_async (RPC_CMD_GRAPH_COMPUTE ,input_ptr ,input_size ); 1032 } 1033return GGML_STATUS_SUCCESS ; 1034} 1035 1036static void ggml_backend_rpc_event_record (ggml_backend_t backend ,ggml_backend_event_t event ) { 1037ggml_backend_rpc_context * rpc_ctx = (ggml_backend_rpc_context * )backend -> context ; 1038rpc_ctx -> dispatcher -> event_record (event ); 1039} 1040 1041static void ggml_backend_rpc_event_wait (ggml_backend_t backend ,ggml_backend_event_t event ) { 1042// this is noop for RPC as we have a single stream 1043GGML_UNUSED (backend ); 1044GGML_UNUSED (event ); 1045} 1046 1047static ggml_backend_i ggml_backend_rpc_interface = { 1048/* .get_name = */ ggml_backend_rpc_name , 1049/* .free = */ ggml_backend_rpc_free , 1050/* .set_tensor_async = */ ggml_backend_rpc_set_tensor_async , 1051/* .get_tensor_async = */ ggml_backend_rpc_get_tensor_async , 1052/* .set_tensor_2d_async = */ NULL , 1053/* .get_tensor_2d_async = */ NULL , 1054/* .cpy_tensor_async = */ NULL , 1055/* .synchronize = */ ggml_backend_rpc_synchronize , 1056/* .graph_plan_create = */ NULL , 1057/* .graph_plan_free = */ NULL , 1058/* .graph_plan_update = */ NULL , 1059/* .graph_plan_compute = */ NULL , 1060/* .graph_compute = */ ggml_backend_rpc_graph_compute , 1061/* .event_record = */ ggml_backend_rpc_event_record , 1062/* .event_wait = */ ggml_backend_rpc_event_wait , 1063/* .graph_optimize = */ NULL , 1064}; 1065 1066ggml_backend_buffer_type_t ggml_backend_rpc_buffer_type (const char * endpoint ,uint32_t device ) { 1067static std::mutex mutex ; 1068 std::lock_guard < std::mutex > lock (mutex ); 1069 std::string buft_name = "RPC" + std::to_string (device )+ "[" + std::string (endpoint )+ "]" ; 1070// NOTE: buffer types are allocated and never freed; this is by design 1071static std::unordered_map < std::string ,ggml_backend_buffer_type_t > buft_map ; 1072auto it = buft_map .find (buft_name ); 1073if (it != buft_map .end ()) { 1074return it -> second ; 1075 } 1076auto dispatcher = get_dispatcher (endpoint ); 1077size_t alignment = get_alignment (dispatcher ,device ); 1078size_t max_size = get_max_size (dispatcher ,device ); 1079ggml_backend_rpc_buffer_type_context * buft_ctx = new ggml_backend_rpc_buffer_type_context { 1080/* .endpoint = */ endpoint , 1081/* .device = */ device , 1082/* .name = */ buft_name , 1083/* .alignment = */ alignment , 1084/* .max_size = */ max_size 1085 }; 1086auto reg = ggml_backend_rpc_add_server (endpoint ); 1087ggml_backend_buffer_type_t buft = new ggml_backend_buffer_type { 1088/* .iface = */ ggml_backend_rpc_buffer_type_interface , 1089/* .device = */ ggml_backend_reg_dev_get (reg ,device ), 1090/* .context = */ buft_ctx 1091 }; 1092buft_map [buft_name ]= buft ; 1093return buft ; 1094} 1095 1096ggml_backend_t ggml_backend_rpc_init (const char * endpoint ,uint32_t device ) { 1097 std::string dev_name = "RPC" + std::to_string (device )+ "[" + std::string (endpoint )+ "]" ; 1098auto dispatcher = get_dispatcher (endpoint ); 1099ggml_backend_rpc_context * ctx = new ggml_backend_rpc_context { 1100/* .dispatcher = */ dispatcher , 1101/* .device = */ device , 1102/* .name = */ dev_name , 1103 }; 1104auto reg = ggml_backend_rpc_add_server (endpoint ); 1105ggml_backend_t backend = new ggml_backend { 1106/* .guid = */ ggml_backend_rpc_guid (), 1107/* .iface = */ ggml_backend_rpc_interface , 1108/* .device = */ ggml_backend_reg_dev_get (reg ,device ), 1109/* .context = */ ctx 1110 }; 1111return backend ; 1112} 1113 1114bool ggml_backend_is_rpc (ggml_backend_t backend ) { 1115return backend != NULL && ggml_guid_matches (backend -> guid ,ggml_backend_rpc_guid ()); 1116} 1117 1118void ggml_backend_rpc_get_device_memory (const char * endpoint ,uint32_t device ,size_t * free ,size_t * total ) { 1119auto dispatcher = get_dispatcher (endpoint ); 1120auto request = std::make_shared < rpc_msg_get_device_memory_req > (); 1121request -> device = device ; 1122rpc_msg_get_device_memory_rsp response ; 1123dispatcher -> send (RPC_CMD_GET_DEVICE_MEMORY ,request ,sizeof (* request ),& response ,sizeof (response )); 1124* free = response .free_mem ; 1125* total = response .total_mem ; 1126} 1127 1128// RPC server-side implementation 1129 1130class rpc_server { 1131public : 1132rpc_server (std::vector < ggml_backend_t > all_backends ,const char * cache_dir ) 1133 :backends (std::move (all_backends )),cache_dir (cache_dir ) { 1134stored_graphs .resize (backends .size ()); 1135 } 1136 ~rpc_server (); 1137 1138void hello (rpc_msg_hello_rsp & response ); 1139bool alloc_buffer (const rpc_msg_alloc_buffer_req & request ,rpc_msg_alloc_buffer_rsp & response ); 1140bool get_alignment (const rpc_msg_get_alignment_req & request ,rpc_msg_get_alignment_rsp & response ); 1141bool get_max_size (const rpc_msg_get_max_size_req & request ,rpc_msg_get_max_size_rsp & response ); 1142bool buffer_get_base (const rpc_msg_buffer_get_base_req & request ,rpc_msg_buffer_get_base_rsp & response ); 1143bool free_buffer (const rpc_msg_free_buffer_req & request ); 1144bool buffer_clear (const rpc_msg_buffer_clear_req & request ); 1145bool memset_tensor (const rpc_msg_memset_tensor_req & request ); 1146bool set_tensor (const std::vector < uint8_t > & input ); 1147bool set_tensor_hash (const rpc_msg_set_tensor_hash_req & request ,rpc_msg_set_tensor_hash_rsp & response ); 1148bool get_tensor (const rpc_msg_get_tensor_req & request , std::vector < uint8_t > & response ); 1149bool copy_tensor (const rpc_msg_copy_tensor_req & request ,rpc_msg_copy_tensor_rsp & response ); 1150bool graph_compute (const std::vector < uint8_t > & input ); 1151bool graph_recompute (const rpc_msg_graph_recompute_req & request ); 1152bool init_tensor (const rpc_msg_init_tensor_req & request ); 1153bool get_alloc_size (const rpc_msg_get_alloc_size_req & request ,rpc_msg_get_alloc_size_rsp & response ); 1154bool get_device_memory (const rpc_msg_get_device_memory_req & request ,rpc_msg_get_device_memory_rsp & response ); 1155 1156struct stored_graph { 1157 std::vector < uint8_t > buffer ; 1158ggml_cgraph * graph ; 1159 }; 1160 1161private : 1162bool get_cached_file (uint64_t hash , std::vector < uint8_t > & data ); 1163ggml_tensor * deserialize_tensor (struct ggml_context * ctx ,const rpc_tensor * tensor ); 1164ggml_tensor * create_node (uint64_t id , 1165struct ggml_context * ctx , 1166const std::unordered_map < uint64_t ,const rpc_tensor *> & tensor_ptrs , 1167 std::unordered_map < uint64_t ,struct ggml_tensor *> & tensor_map ); 1168 1169 1170 std::vector < ggml_backend_t > backends ; 1171const char * cache_dir ; 1172 std::unordered_set < ggml_backend_buffer_t > buffers ; 1173// store the last computed graph for each backend 1174 std::vector < stored_graph > stored_graphs ; 1175}; 1176 1177void rpc_server::hello (rpc_msg_hello_rsp & response ) { 1178response .major = RPC_PROTO_MAJOR_VERSION ; 1179response .minor = RPC_PROTO_MINOR_VERSION ; 1180response .patch = RPC_PROTO_PATCH_VERSION ; 1181LOG_DBG ("[%s] version: %d.%d.%d\n" ,__func__ ,response .major ,response .minor ,response .patch ); 1182} 1183 1184bool rpc_server::get_alloc_size (const rpc_msg_get_alloc_size_req & request ,rpc_msg_get_alloc_size_rsp & response ) { 1185uint32_t dev_id = request .device ; 1186if (dev_id >=backends .size ()) { 1187return false; 1188 } 1189ggml_backend_buffer_type_t buft ; 1190struct ggml_init_params params { 1191/*.mem_size =*/ ggml_tensor_overhead ()* (1 + GGML_MAX_SRC ), 1192/*.mem_buffer =*/ NULL , 1193/*.no_alloc =*/ true, 1194 }; 1195 1196ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1197GGML_ASSERT (ctx_ptr != nullptr ); 1198ggml_context * ctx = ctx_ptr .get (); 1199 1200ggml_tensor * tensor = deserialize_tensor (ctx ,& request .tensor ); 1201if (tensor == nullptr ) { 1202GGML_LOG_ERROR ("Null tensor pointer passed to server get_alloc_size function.\n" ); 1203return false; 1204 } 1205for (int i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 1206if (request .srcs [i ].id != 0 ) { 1207tensor -> src [i ]= deserialize_tensor (ctx ,& request .srcs [i ]); 1208 } 1209 } 1210 1211LOG_DBG ("[%s] device: %d, buffer: %p, data: %p\n" ,__func__ ,dev_id , (void * )tensor -> buffer ,tensor -> data ); 1212if (tensor -> buffer == nullptr ) { 1213//No buffer allocated. 1214buft = ggml_backend_get_default_buffer_type (backends [dev_id ]); 1215 }else { 1216buft = tensor -> buffer -> buft ; 1217 } 1218 1219response .alloc_size = ggml_backend_buft_get_alloc_size (buft ,tensor ); 1220 1221return true; 1222} 1223 1224bool rpc_server::alloc_buffer (const rpc_msg_alloc_buffer_req & request ,rpc_msg_alloc_buffer_rsp & response ) { 1225uint32_t dev_id = request .device ; 1226if (dev_id >=backends .size ()) { 1227return false; 1228 } 1229ggml_backend_buffer_type_t buft = ggml_backend_get_default_buffer_type (backends [dev_id ]); 1230ggml_backend_buffer_t buffer = ggml_backend_buft_alloc_buffer (buft ,request .size ); 1231response .remote_ptr = 0 ; 1232response .remote_size = 0 ; 1233if (buffer != nullptr ) { 1234response .remote_ptr = reinterpret_cast < uint64_t > (buffer ); 1235response .remote_size = buffer -> size ; 1236LOG_DBG ("[%s] device: %d, size: %" PRIu64 " -> remote_ptr: %" PRIx64 ", remote_size: %" PRIu64 "\n" , 1237__func__ ,dev_id ,request .size ,response .remote_ptr ,response .remote_size ); 1238buffers .insert (buffer ); 1239 }else { 1240LOG_DBG ("[%s] device: %d, size: %" PRIu64 " -> failed\n" ,__func__ ,dev_id ,request .size ); 1241 } 1242return true; 1243} 1244 1245bool rpc_server::get_alignment (const rpc_msg_get_alignment_req & request ,rpc_msg_get_alignment_rsp & response ) { 1246uint32_t dev_id = request .device ; 1247if (dev_id >=backends .size ()) { 1248return false; 1249 } 1250ggml_backend_buffer_type_t buft = ggml_backend_get_default_buffer_type (backends [dev_id ]); 1251size_t alignment = ggml_backend_buft_get_alignment (buft ); 1252LOG_DBG ("[%s] device: %d, alignment: %lu\n" ,__func__ ,dev_id ,alignment ); 1253response .alignment = alignment ; 1254return true; 1255} 1256 1257bool rpc_server::get_max_size (const rpc_msg_get_max_size_req & request ,rpc_msg_get_max_size_rsp & response ) { 1258uint32_t dev_id = request .device ; 1259if (dev_id >=backends .size ()) { 1260return false; 1261 } 1262ggml_backend_buffer_type_t buft = ggml_backend_get_default_buffer_type (backends [dev_id ]); 1263size_t max_size = ggml_backend_buft_get_max_size (buft ); 1264LOG_DBG ("[%s] device: %d, max_size: %lu\n" ,__func__ ,dev_id ,max_size ); 1265response .max_size = max_size ; 1266return true; 1267} 1268 1269bool rpc_server::buffer_get_base (const rpc_msg_buffer_get_base_req & request ,rpc_msg_buffer_get_base_rsp & response ) { 1270LOG_DBG ("[%s] remote_ptr: %" PRIx64 "\n" ,__func__ ,request .remote_ptr ); 1271ggml_backend_buffer_t buffer = reinterpret_cast < ggml_backend_buffer_t > (request .remote_ptr ); 1272if (buffers .find (buffer )== buffers .end ()) { 1273GGML_LOG_ERROR ("[%s] buffer not found\n" ,__func__ ); 1274return false; 1275 } 1276void * base = ggml_backend_buffer_get_base (buffer ); 1277response .base_ptr = reinterpret_cast < uint64_t > (base ); 1278return true; 1279} 1280 1281bool rpc_server::free_buffer (const rpc_msg_free_buffer_req & request ) { 1282LOG_DBG ("[%s] remote_ptr: %" PRIx64 "\n" ,__func__ ,request .remote_ptr ); 1283ggml_backend_buffer_t buffer = reinterpret_cast < ggml_backend_buffer_t > (request .remote_ptr ); 1284if (buffers .find (buffer )== buffers .end ()) { 1285GGML_LOG_ERROR ("[%s] buffer not found\n" ,__func__ ); 1286return false; 1287 } 1288ggml_backend_buffer_free (buffer ); 1289buffers .erase (buffer ); 1290return true; 1291} 1292 1293bool rpc_server::buffer_clear (const rpc_msg_buffer_clear_req & request ) { 1294LOG_DBG ("[%s] remote_ptr: %" PRIx64 ", value: %u\n" ,__func__ ,request .remote_ptr ,request .value ); 1295ggml_backend_buffer_t buffer = reinterpret_cast < ggml_backend_buffer_t > (request .remote_ptr ); 1296if (buffers .find (buffer )== buffers .end ()) { 1297GGML_LOG_ERROR ("[%s] buffer not found\n" ,__func__ ); 1298return false; 1299 } 1300ggml_backend_buffer_clear (buffer ,request .value ); 1301return true; 1302} 1303 1304bool rpc_server::memset_tensor (const rpc_msg_memset_tensor_req & request ) { 1305struct ggml_init_params params { 1306/*.mem_size =*/ ggml_tensor_overhead (), 1307/*.mem_buffer =*/ NULL , 1308/*.no_alloc =*/ true, 1309 }; 1310ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1311GGML_ASSERT (ctx_ptr != nullptr ); 1312ggml_context * ctx = ctx_ptr .get (); 1313ggml_tensor * tensor = deserialize_tensor (ctx ,& request .tensor ); 1314if (tensor == nullptr || tensor -> buffer == nullptr ) { 1315GGML_LOG_ERROR ("[%s] error deserializing tensor\n" ,__func__ ); 1316return false; 1317 } 1318 1319const uint64_t tensor_size = ggml_nbytes (tensor ); 1320if (request .offset > tensor_size || request .size > tensor_size - request .offset ) { 1321GGML_LOG_ERROR ("[%s] tensor region (offset=%" PRIu64 ", size=%" PRIu64 ") out of tensor bounds [0, %" PRIu64 ")\n" , 1322__func__ ,request .offset ,request .size ,tensor_size ); 1323return false; 1324 } 1325 1326const uint64_t buffer_start = (uint64_t )ggml_backend_buffer_get_base (tensor -> buffer ); 1327const uint64_t buffer_size = ggml_backend_buffer_get_size (tensor -> buffer ); 1328if (request .tensor .data < buffer_start ) { 1329GGML_LOG_ERROR ("[%s] tensor data before buffer start\n" ,__func__ ); 1330return false; 1331 } 1332const uint64_t data_offset = request .tensor .data - buffer_start ; 1333if (data_offset > buffer_size || 1334request .offset > buffer_size - data_offset || 1335request .size > buffer_size - data_offset - request .offset ) { 1336GGML_LOG_ERROR ("[%s] tensor region out of buffer bounds\n" ,__func__ ); 1337return false; 1338 } 1339if (tensor -> buffer -> iface .memset_tensor == nullptr ) { 1340GGML_LOG_ERROR ("[%s] memset not implemented by backend buffer\n" ,__func__ ); 1341return false; 1342 } 1343 1344LOG_DBG ("[%s] buffer: %p, data: %p, offset: %" PRIu64 ", size: %" PRIu64 ", value: %u\n" , 1345__func__ , (void * )tensor -> buffer ,tensor -> data ,request .offset ,request .size ,request .value ); 1346ggml_backend_tensor_memset (tensor ,request .value ,request .offset ,request .size ); 1347return true; 1348} 1349 1350ggml_tensor * rpc_server::deserialize_tensor (struct ggml_context * ctx ,const rpc_tensor * tensor ) { 1351// Validate tensor type before using it 1352if (tensor -> type >=GGML_TYPE_COUNT ) { 1353GGML_LOG_ERROR ("[%s] invalid tensor type received: %u\n" ,__func__ ,tensor -> type ); 1354return nullptr ; 1355 } 1356 1357// Fix: Prevent division by zero if blck_size is 0 (e.g., deprecated types) 1358if (ggml_blck_size ((enum ggml_type )tensor -> type )== 0 ) { 1359GGML_LOG_ERROR ("[%s] invalid tensor type received (blck_size is 0): %u\n" ,__func__ ,tensor -> type ); 1360return nullptr ; 1361 } 1362 1363ggml_tensor * result = ggml_new_tensor_4d (ctx , (ggml_type )tensor -> type , 1364tensor -> ne [0 ],tensor -> ne [1 ],tensor -> ne [2 ],tensor -> ne [3 ]); 1365 1366// ggml_new_tensor_4d might fail if dimensions are invalid, although less likely to crash than invalid type 1367if (result == nullptr ) { 1368GGML_LOG_ERROR ("[%s] ggml_new_tensor_4d failed for type %u\n" ,__func__ ,tensor -> type ); 1369return nullptr ; 1370 } 1371 1372for (uint32_t i = 0 ;i < GGML_MAX_DIMS ;i ++ ) { 1373result -> nb [i ]= tensor -> nb [i ]; 1374 } 1375result -> buffer = reinterpret_cast < ggml_backend_buffer_t > (tensor -> buffer ); 1376if (result -> buffer && buffers .find (result -> buffer )== buffers .end ()) { 1377result -> buffer = nullptr ; 1378 } 1379 1380if (result -> buffer ) { 1381// require that the tensor data does not go beyond the buffer end 1382uint64_t tensor_size = (uint64_t )ggml_nbytes (result ); 1383uint64_t buffer_start = (uint64_t )ggml_backend_buffer_get_base (result -> buffer ); 1384uint64_t buffer_size = (uint64_t )ggml_backend_buffer_get_size (result -> buffer ); 1385GGML_ASSERT (tensor -> data + tensor_size >=tensor -> data );// check for overflow 1386GGML_ASSERT (tensor -> data >=buffer_start && tensor -> data + tensor_size <=buffer_start + buffer_size ); 1387 } 1388 1389result -> op = (ggml_op )tensor -> op ; 1390for (uint32_t i = 0 ;i < GGML_MAX_OP_PARAMS /sizeof (int32_t );i ++ ) { 1391result -> op_params [i ]= tensor -> op_params [i ]; 1392 } 1393result -> flags = tensor -> flags ; 1394result -> data = reinterpret_cast < void *> (tensor -> data ); 1395ggml_set_name (result ,tensor -> name ); 1396return result ; 1397} 1398 1399 1400bool rpc_server::set_tensor (const std::vector < uint8_t > & input ) { 1401// serialization format: | rpc_tensor | offset (8 bytes) | data (size bytes) | 1402if (input .size ()< sizeof (rpc_tensor )+ sizeof (uint64_t )) { 1403return false; 1404 } 1405const rpc_tensor * in_tensor = (const rpc_tensor * )input .data (); 1406uint64_t offset ; 1407memcpy (& offset ,input .data ()+ sizeof (rpc_tensor ),sizeof (offset )); 1408const size_t size = input .size ()- sizeof (rpc_tensor )- sizeof (offset ); 1409 1410struct ggml_init_params params { 1411/*.mem_size =*/ ggml_tensor_overhead (), 1412/*.mem_buffer =*/ NULL , 1413/*.no_alloc =*/ true, 1414 }; 1415ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1416GGML_ASSERT (ctx_ptr != nullptr ); 1417ggml_context * ctx = ctx_ptr .get (); 1418ggml_tensor * tensor = deserialize_tensor (ctx ,in_tensor ); 1419if (tensor == nullptr || tensor -> buffer == nullptr ) { 1420GGML_LOG_ERROR ("[%s] error deserializing tensor\n" ,__func__ ); 1421return false; 1422 } 1423LOG_DBG ("[%s] buffer: %p, data: %p, offset: %" PRIu64 ", size: %zu\n" ,__func__ , (void * )tensor -> buffer ,tensor -> data ,offset ,size ); 1424 1425// sanitize tensor->data 1426 { 1427const size_t p0 = (size_t )ggml_backend_buffer_get_base (tensor -> buffer ); 1428const size_t p1 = p0 + ggml_backend_buffer_get_size (tensor -> buffer ); 1429 1430if (in_tensor -> data + offset < p0 || in_tensor -> data + offset >=p1 || size > (p1 - in_tensor -> data - offset )) { 1431GGML_LOG_ERROR ("[%s] tensor data region (data=0x%" PRIx64 ", offset=%" PRIu64 ", size=%zu) out of buffer bounds [0x%zx, 0x%zx)\n" , 1432__func__ ,in_tensor -> data ,offset ,size ,p0 ,p1 ); 1433return false; 1434 } 1435 } 1436 1437const void * data = input .data ()+ sizeof (rpc_tensor )+ sizeof (offset ); 1438if (cache_dir && size > HASH_THRESHOLD ) { 1439uint64_t hash = fnv_hash ((const uint8_t * )data ,size ); 1440char hash_str [17 ]; 1441snprintf (hash_str ,sizeof (hash_str ),"%016" PRIx64 ,hash ); 1442// save to cache_dir/hash_str 1443 fs::path cache_file = fs::path (cache_dir ) /hash_str ; 1444 std::ofstream ofs (cache_file , std::ios::binary ); 1445ofs .write ((const char * )data ,size ); 1446GGML_LOG_INFO ("[%s] saved to '%s'\n" ,__func__ ,cache_file .string ().c_str ()); 1447 } 1448ggml_backend_tensor_set (tensor ,data ,offset ,size ); 1449return true; 1450} 1451 1452bool rpc_server::get_cached_file (uint64_t hash , std::vector < uint8_t > & data ) { 1453if (!cache_dir ) { 1454return false; 1455 } 1456char hash_str [17 ]; 1457snprintf (hash_str ,sizeof (hash_str ),"%016" PRIx64 ,hash ); 1458 fs::path cache_file = fs::path (cache_dir ) /hash_str ; 1459 std::error_code ec ; 1460if (!fs::exists (cache_file ,ec )) { 1461return false; 1462 } 1463 std::ifstream ifs (cache_file , std::ios::binary ); 1464ifs .seekg (0 , std::ios::end ); 1465size_t size = ifs .tellg (); 1466ifs .seekg (0 , std::ios::beg ); 1467data .resize (size ); 1468ifs .read ((char * )data .data (),size ); 1469return true; 1470} 1471 1472bool rpc_server::set_tensor_hash (const rpc_msg_set_tensor_hash_req & request ,rpc_msg_set_tensor_hash_rsp & response ) 1473{ 1474 std::vector < uint8_t > cached_file ; 1475if (!get_cached_file (request .hash ,cached_file )) { 1476response .result = 0 ; 1477return true; 1478 } 1479size_t size = cached_file .size (); 1480struct ggml_init_params params { 1481/*.mem_size =*/ ggml_tensor_overhead (), 1482/*.mem_buffer =*/ NULL , 1483/*.no_alloc =*/ true, 1484 }; 1485ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1486GGML_ASSERT (ctx_ptr != nullptr ); 1487ggml_context * ctx = ctx_ptr .get (); 1488ggml_tensor * tensor = deserialize_tensor (ctx ,& request .tensor ); 1489if (tensor == nullptr || tensor -> buffer == nullptr ) { 1490GGML_LOG_ERROR ("[%s] error deserializing tensor\n" ,__func__ ); 1491return false; 1492 } 1493LOG_DBG ("[%s] buffer: %p, data: %p, offset: %" PRIu64 ", size: %zu, hash: %" PRIx64 "\n" , 1494__func__ , (void * )tensor -> buffer ,tensor -> data ,request .offset ,size ,request .hash ); 1495 1496// sanitize tensor->data 1497 { 1498const size_t p0 = (size_t )ggml_backend_buffer_get_base (tensor -> buffer ); 1499const size_t p1 = p0 + ggml_backend_buffer_get_size (tensor -> buffer ); 1500 1501if (request .tensor .data + request .offset < p0 1502|| request .tensor .data + request .offset >=p1 1503|| size > (p1 - request .tensor .data - request .offset )) { 1504GGML_LOG_ERROR ("[%s] tensor data region (data=0x%" PRIx64 ", offset=%" PRIu64 ", size=%zu, hash=0x%" PRIx64 ") out of buffer bounds [0x%zx, 0x%zx)\n" , 1505__func__ ,request .tensor .data ,request .offset ,size ,request .hash ,p0 ,p1 ); 1506return false; 1507 } 1508 } 1509ggml_backend_tensor_set (tensor ,cached_file .data (),request .offset ,size ); 1510response .result = 1 ; 1511return true; 1512} 1513 1514bool rpc_server::init_tensor (const rpc_msg_init_tensor_req & request ) { 1515struct ggml_init_params params { 1516/*.mem_size =*/ ggml_tensor_overhead (), 1517/*.mem_buffer =*/ NULL , 1518/*.no_alloc =*/ true, 1519 }; 1520ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1521GGML_ASSERT (ctx_ptr != nullptr ); 1522ggml_context * ctx = ctx_ptr .get (); 1523ggml_tensor * tensor = deserialize_tensor (ctx ,& request .tensor ); 1524if (tensor == nullptr ) { 1525GGML_LOG_ERROR ("Null tensor pointer passed to server init_tensor function.\n" ); 1526return false; 1527 } 1528LOG_DBG ("[%s] buffer: %p, data: %p\n" ,__func__ , (void * )tensor -> buffer ,tensor -> data ); 1529// Call the backend's buffer_init_tensor function 1530ggml_backend_buffer_t buffer = tensor -> buffer ; 1531if (buffer && buffer -> iface .init_tensor ) { 1532buffer -> iface .init_tensor (buffer ,tensor ); 1533 }else { 1534if (!buffer ) { 1535GGML_LOG_ERROR ("Tensor with null buffer passed to init_tensor function\n" ); 1536 } 1537 } 1538 1539if (tensor -> extra != nullptr ) { 1540// This pointer can either be passed around client/server, or probably better stored server-side and kept track of. 1541// Currently unimplemented. 1542GGML_LOG_ERROR ("tensor->extra populated by the backend, this is currently unsupported.\n" ); 1543return false; 1544 } 1545 1546return true; 1547} 1548 1549bool rpc_server::get_tensor (const rpc_msg_get_tensor_req & request , std::vector < uint8_t > & response ) { 1550struct ggml_init_params params { 1551/*.mem_size =*/ ggml_tensor_overhead (), 1552/*.mem_buffer =*/ NULL , 1553/*.no_alloc =*/ true, 1554 }; 1555ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1556GGML_ASSERT (ctx_ptr != nullptr ); 1557ggml_context * ctx = ctx_ptr .get (); 1558ggml_tensor * tensor = deserialize_tensor (ctx ,& request .tensor ); 1559if (tensor == nullptr || tensor -> buffer == nullptr ) { 1560GGML_LOG_ERROR ("[%s] error deserializing tensor\n" ,__func__ ); 1561return false; 1562 } 1563LOG_DBG ("[%s] buffer: %p, data: %p, offset: %" PRIu64 ", size: %" PRIu64 "\n" ,__func__ , (void * )tensor -> buffer ,tensor -> data ,request .offset ,request .size ); 1564 1565// sanitize tensor->data 1566 { 1567const size_t p0 = (size_t )ggml_backend_buffer_get_base (tensor -> buffer ); 1568const size_t p1 = p0 + ggml_backend_buffer_get_size (tensor -> buffer ); 1569 1570if (request .tensor .data + request .offset < p0 || 1571request .tensor .data + request .offset >=p1 || 1572request .size > (p1 - request .tensor .data - request .offset )) { 1573GGML_LOG_ERROR ("[%s] requested tensor region (data=0x%" PRIx64 ", offset=%" PRIu64 ", size=%" PRIu64 ") out of buffer bounds [0x%zx, 0x%zx)\n" , 1574__func__ ,request .tensor .data ,request .offset ,request .size ,p0 ,p1 ); 1575return false; 1576 } 1577 } 1578 1579response .resize (request .size ,0 ); 1580ggml_backend_tensor_get (tensor ,response .data (),request .offset ,request .size ); 1581return true; 1582} 1583 1584bool rpc_server::copy_tensor (const rpc_msg_copy_tensor_req & request ,rpc_msg_copy_tensor_rsp & response ) { 1585struct ggml_init_params params { 1586/*.mem_size =*/ 2 * ggml_tensor_overhead (), 1587/*.mem_buffer =*/ NULL , 1588/*.no_alloc =*/ true, 1589 }; 1590ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1591GGML_ASSERT (ctx_ptr != nullptr ); 1592ggml_context * ctx = ctx_ptr .get (); 1593 1594ggml_tensor * src = deserialize_tensor (ctx ,& request .src ); 1595ggml_tensor * dst = deserialize_tensor (ctx ,& request .dst ); 1596if (src == nullptr || dst == nullptr || src -> buffer == nullptr || dst -> buffer == nullptr ) { 1597GGML_LOG_ERROR ("[%s] error deserializing tensors\n" ,__func__ ); 1598return false; 1599 } 1600 1601uint64_t src_size = (uint64_t )ggml_nbytes (src ); 1602uint64_t dst_data = (uint64_t )dst -> data ; 1603uint64_t dst_base = (uint64_t )ggml_backend_buffer_get_base (dst -> buffer ); 1604uint64_t dst_buf_sz = (uint64_t )ggml_backend_buffer_get_size (dst -> buffer ); 1605 1606if (dst_data + src_size > dst_base + dst_buf_sz ) { 1607GGML_LOG_ERROR ("[%s] out-of-bounds write in rpc_server::copy_tensor:\n" 1608" write range : [0x%" PRIx64 ", 0x%" PRIx64 "]\n" 1609" buffer base: [0x%" PRIx64 ", 0x%" PRIx64 "]\n" , 1610__func__ , 1611dst_data , 1612dst_data + src_size , 1613dst_base , 1614dst_base + dst_buf_sz ); 1615return false; 1616 } 1617 1618LOG_DBG ("[%s] src->buffer: %p, dst->buffer: %p\n" , 1619__func__ , (void * )src -> buffer , (void * )dst -> buffer ); 1620 1621response .result = ggml_backend_buffer_copy_tensor (src ,dst ); 1622return true; 1623} 1624 1625ggml_tensor * rpc_server::create_node (uint64_t id , 1626struct ggml_context * ctx , 1627const std::unordered_map < uint64_t ,const rpc_tensor *> & tensor_ptrs , 1628 std::unordered_map < uint64_t ,struct ggml_tensor *> & tensor_map ) { 1629if (tensor_map .find (id )!= tensor_map .end ()) { 1630return tensor_map [id ]; 1631 } 1632// Safely find the tensor pointer 1633auto it_ptr = tensor_ptrs .find (id ); 1634if (it_ptr == tensor_ptrs .end ()) { 1635return nullptr ; 1636 } 1637const rpc_tensor * tensor = it_ptr -> second ; 1638 1639struct ggml_tensor * result = deserialize_tensor (ctx ,tensor ); 1640if (result == nullptr ) { 1641return nullptr ; 1642 } 1643if (result -> buffer == nullptr && result -> data != nullptr ) { 1644GGML_LOG_ERROR ("[%s] invalid data ptr" ,__func__ ); 1645return nullptr ; 1646 } 1647tensor_map [id ]= result ; 1648for (int i = 0 ;i < GGML_MAX_SRC ;i ++ ) { 1649// Check if the source ID is 0 before calling create_node recursively 1650if (tensor -> src [i ]== 0 ) { 1651result -> src [i ]= nullptr ; 1652 }else { 1653result -> src [i ]= create_node (tensor -> src [i ],ctx ,tensor_ptrs ,tensor_map ); 1654// If the recursive call failed for a non-zero ID, propagate the error 1655if (result -> src [i ]== nullptr ) { 1656GGML_LOG_ERROR ("[%s] failed to create source node %d (src_id=%" PRIu64 ") for node id %" PRIu64 "\n" , 1657__func__ ,i ,tensor -> src [i ],id ); 1658// Must return nullptr to signal failure up the call stack 1659return nullptr ; 1660 } 1661 } 1662 } 1663 1664// Handle view_src similarly 1665if (tensor -> view_src == 0 ) { 1666result -> view_src = nullptr ; 1667 }else { 1668result -> view_src = create_node (tensor -> view_src ,ctx ,tensor_ptrs ,tensor_map ); 1669// If the recursive call failed for a non-zero ID, propagate the error 1670if (result -> view_src == nullptr ) { 1671GGML_LOG_ERROR ("[%s] failed to create view_src node (view_src_id=%" PRIu64 ") for node id %" PRIu64 "\n" , 1672__func__ ,tensor -> view_src ,id ); 1673// Must return nullptr to signal failure up the call stack 1674return nullptr ; 1675 } 1676 } 1677result -> view_offs = tensor -> view_offs ; 1678return result ; 1679} 1680 1681bool rpc_server::graph_compute (const std::vector < uint8_t > & input ) { 1682// serialization format: 1683// | device (4 bytes) | n_nodes (4 bytes) | nodes (n_nodes * sizeof(uint64_t) | n_tensors (4 bytes) | tensors (n_tensors * sizeof(rpc_tensor)) | 1684if (input .size ()< 2 * sizeof (uint32_t )) { 1685return false; 1686 } 1687const uint8_t * src = input .data (); 1688uint32_t device ; 1689memcpy (& device ,src ,sizeof (device )); 1690src += sizeof (device ); 1691if (device >=backends .size ()) { 1692return false; 1693 } 1694uint32_t n_nodes ; 1695memcpy (& n_nodes ,src ,sizeof (n_nodes )); 1696src += sizeof (n_nodes ); 1697if (input .size ()< 2 * sizeof (uint32_t )+ n_nodes * sizeof (uint64_t )+ sizeof (uint32_t )) { 1698return false; 1699 } 1700const uint64_t * nodes = (const uint64_t * )src ; 1701src += n_nodes * sizeof (uint64_t ); 1702uint32_t n_tensors ; 1703memcpy (& n_tensors ,src ,sizeof (n_tensors )); 1704src += sizeof (n_tensors ); 1705if (input .size ()< 2 * sizeof (uint32_t )+ n_nodes * sizeof (uint64_t )+ sizeof (uint32_t )+ n_tensors * sizeof (rpc_tensor )) { 1706return false; 1707 } 1708const rpc_tensor * tensors = (const rpc_tensor * )src ; 1709LOG_DBG ("[%s] device: %u, n_nodes: %u, n_tensors: %u\n" ,__func__ ,device ,n_nodes ,n_tensors ); 1710 1711size_t buf_size = ggml_tensor_overhead ()* (n_nodes + n_tensors )+ ggml_graph_overhead_custom (n_nodes , false); 1712if (stored_graphs [device ].buffer .size ()< buf_size ) { 1713stored_graphs [device ].buffer .resize (buf_size ); 1714 } 1715struct ggml_init_params params = { 1716/*.mem_size =*/ buf_size , 1717/*.mem_buffer =*/ stored_graphs [device ].buffer .data (), 1718/*.no_alloc =*/ true, 1719 }; 1720ggml_context_ptr ctx_ptr {ggml_init (params ) }; 1721GGML_ASSERT (ctx_ptr != nullptr ); 1722ggml_context * ctx = ctx_ptr .get (); 1723struct ggml_cgraph * graph = ggml_new_graph_custom (ctx ,n_nodes , false); 1724graph -> n_nodes = n_nodes ; 1725 std::unordered_map < uint64_t ,const rpc_tensor *> tensor_ptrs ; 1726tensor_ptrs .reserve (n_tensors ); 1727for (uint32_t i = 0 ;i < n_tensors ;i ++ ) { 1728tensor_ptrs .emplace (tensors [i ].id ,& tensors [i ]); 1729 } 1730 std::unordered_map < uint64_t ,ggml_tensor *> tensor_map ; 1731tensor_map .reserve (n_nodes ); 1732for (uint32_t i = 0 ;i < n_nodes ;i ++ ) { 1733int64_t id ; 1734memcpy (& id ,& nodes [i ],sizeof (id )); 1735graph -> nodes [i ]= create_node (id ,ctx ,tensor_ptrs ,tensor_map ); 1736 1737// Check if create_node failed for a *non-zero* ID. 1738// If id was 0, create_node returning nullptr is expected. 1739// If id was non-zero and create_node returned nullptr, it indicates a deserialization error. 1740if (graph -> nodes [i ]== nullptr && id != 0 ) { 1741GGML_LOG_ERROR ("[%s] failed to create graph node %d (id=%" PRId64 ")\n" ,__func__ ,i ,id ); 1742return false; 1743 } 1744if (graph -> nodes [i ]!= nullptr ) { 1745const size_t hash_pos = ggml_hash_insert (& graph -> visited_hash_set ,graph -> nodes [i ]); 1746graph -> use_counts [hash_pos ]= tensor_ptrs .at (id )-> use_count ; 1747 } 1748 } 1749ggml_status status = ggml_backend_graph_compute (backends [device ],graph ); 1750GGML_ASSERT (status == GGML_STATUS_SUCCESS && "Unsuccessful graph computations are not supported with RPC" ); 1751stored_graphs [device ].graph = graph ; 1752return true; 1753} 1754 1755bool rpc_server::graph_recompute (const rpc_msg_graph_recompute_req & request ) { 1756uint32_t device = request .device ; 1757if (device >=backends .size ()) { 1758return false; 1759 } 1760if (stored_graphs [device ].graph == nullptr ) { 1761return false; 1762 } 1763ggml_cgraph * graph = stored_graphs [device ].graph ; 1764LOG_DBG ("[%s] device: %u\n" ,__func__ ,device ); 1765ggml_status status = ggml_backend_graph_compute (backends [device ],graph ); 1766GGML_ASSERT (status == GGML_STATUS_SUCCESS && "Unsuccessful graph computations are not supported with RPC" ); 1767return true; 1768} 1769 1770bool rpc_server::get_device_memory (const rpc_msg_get_device_memory_req & request ,rpc_msg_get_device_memory_rsp & response ) { 1771uint32_t dev_id = request .device ; 1772if (dev_id >=backends .size ()) { 1773return false; 1774 } 1775size_t free ,total ; 1776ggml_backend_dev_t dev = ggml_backend_get_device (backends [dev_id ]); 1777ggml_backend_dev_memory (dev ,& free ,& total ); 1778response .free_mem = free ; 1779response .total_mem = total ; 1780LOG_DBG ("[%s] device: %u, free_mem: %" PRIu64 ", total_mem: %" PRIu64 "\n" ,__func__ ,dev_id ,response .free_mem ,response .total_mem ); 1781return true; 1782} 1783 1784rpc_server::~rpc_server () { 1785for (auto buffer :buffers ) { 1786ggml_backend_buffer_free (buffer ); 1787 } 1788} 1789 1790static void rpc_serve_client (const std::vector < ggml_backend_t > & backends ,const char * cache_dir , 1791socket_ptr sock ) { 1792rpc_server server (backends ,cache_dir ); 1793uint8_t cmd ; 1794if (!sock -> recv_data (& cmd ,1 )) { 1795return ; 1796 } 1797if (cmd != RPC_CMD_HELLO ) { 1798GGML_LOG_ERROR ("Expected HELLO command, update client\n" ); 1799return ; 1800 } 1801 1802// Read input_size and validate protocol version 1803uint64_t hello_input_size ; 1804if (!sock -> recv_data (& hello_input_size ,sizeof (hello_input_size ))) { 1805return ; 1806 } 1807 1808if (hello_input_size != sizeof (rpc_msg_hello_req )) { 1809GGML_LOG_ERROR ("HELLO request size mismatch (%zu vs %zu) — client needs upgrade to protocol v%d.x\n" , 1810 (size_t )hello_input_size ,sizeof (rpc_msg_hello_req ),RPC_PROTO_MAJOR_VERSION ); 1811return ; 1812 } 1813 1814rpc_msg_hello_req req = {}; 1815if (!sock -> recv_data (& req ,sizeof (req ))) { 1816return ; 1817 } 1818 1819rpc_msg_hello_rsp rsp = {}; 1820server .hello (rsp ); 1821// Advertise server transport capabilities based on client's caps 1822sock -> get_caps (rsp .conn_caps ); 1823if (!send_msg (sock ,& rsp ,sizeof (rsp ))) { 1824return ; 1825 } 1826 1827// Activate transport upgrade using client's caps 1828sock -> update_caps (req .conn_caps ); 1829while (true) { 1830if (!sock -> recv_data (& cmd ,1 )) { 1831break ; 1832 } 1833if (cmd >=RPC_CMD_COUNT ) { 1834// fail fast if the command is invalid 1835GGML_LOG_ERROR ("Unknown command: %d\n" ,cmd ); 1836break ; 1837 } 1838switch (cmd ) { 1839case RPC_CMD_HELLO : { 1840// HELLO command is handled above 1841return ; 1842 } 1843case RPC_CMD_DEVICE_COUNT : { 1844if (!recv_msg (sock ,nullptr ,0 )) { 1845return ; 1846 } 1847rpc_msg_device_count_rsp response ; 1848response .device_count = backends .size (); 1849if (!send_msg (sock ,& response ,sizeof (response ))) { 1850return ; 1851 } 1852break ; 1853 } 1854case RPC_CMD_ALLOC_BUFFER : { 1855rpc_msg_alloc_buffer_req request ; 1856if (!recv_msg (sock ,& request ,sizeof (request ))) { 1857return ; 1858 } 1859rpc_msg_alloc_buffer_rsp response ; 1860if (!server .alloc_buffer (request ,response )) { 1861return ; 1862 } 1863if (!send_msg (sock ,& response ,sizeof (response ))) { 1864return ; 1865 } 1866break ; 1867 } 1868case RPC_CMD_GET_ALLOC_SIZE : { 1869rpc_msg_get_alloc_size_req request ; 1870if (!recv_msg (sock ,& request ,sizeof (request ))) { 1871return ; 1872 } 1873rpc_msg_get_alloc_size_rsp response ; 1874if (!server .get_alloc_size (request ,response )) { 1875return ; 1876 } 1877if (!send_msg (sock ,& response ,sizeof (response ))) { 1878return ; 1879 } 1880break ; 1881 } 1882case RPC_CMD_GET_ALIGNMENT : { 1883rpc_msg_get_alignment_req request ; 1884if (!recv_msg (sock ,& request ,sizeof (request ))) { 1885return ; 1886 } 1887rpc_msg_get_alignment_rsp response ; 1888if (!server .get_alignment (request ,response )) { 1889return ; 1890 } 1891if (!send_msg (sock ,& response ,sizeof (response ))) { 1892return ; 1893 } 1894break ; 1895 } 1896case RPC_CMD_GET_MAX_SIZE : { 1897rpc_msg_get_max_size_req request ; 1898if (!recv_msg (sock ,& request ,sizeof (request ))) { 1899return ; 1900 } 1901rpc_msg_get_max_size_rsp response ; 1902if (!server .get_max_size (request ,response )) { 1903return ; 1904 } 1905if (!send_msg (sock ,& response ,sizeof (response ))) { 1906return ; 1907 } 1908break ; 1909 } 1910case RPC_CMD_BUFFER_GET_BASE : { 1911rpc_msg_buffer_get_base_req request ; 1912if (!recv_msg (sock ,& request ,sizeof (request ))) { 1913return ; 1914 } 1915rpc_msg_buffer_get_base_rsp response ; 1916if (!server .buffer_get_base (request ,response )) { 1917return ; 1918 } 1919if (!send_msg (sock ,& response ,sizeof (response ))) { 1920return ; 1921 } 1922break ; 1923 } 1924case RPC_CMD_FREE_BUFFER : { 1925rpc_msg_free_buffer_req request ; 1926if (!recv_msg (sock ,& request ,sizeof (request ))) { 1927return ; 1928 } 1929if (!server .free_buffer (request )) { 1930return ; 1931 } 1932break ; 1933 } 1934case RPC_CMD_BUFFER_CLEAR : { 1935rpc_msg_buffer_clear_req request ; 1936if (!recv_msg (sock ,& request ,sizeof (request ))) { 1937return ; 1938 } 1939if (!server .buffer_clear (request )) { 1940return ; 1941 } 1942break ; 1943 } 1944case RPC_CMD_MEMSET_TENSOR : { 1945rpc_msg_memset_tensor_req request ; 1946if (!recv_msg (sock ,& request ,sizeof (request ))) { 1947return ; 1948 } 1949if (!server .memset_tensor (request )) { 1950return ; 1951 } 1952break ; 1953 } 1954case RPC_CMD_SET_TENSOR : { 1955 std::vector < uint8_t > input ; 1956if (!recv_msg (sock ,input )) { 1957return ; 1958 } 1959if (!server .set_tensor (input )) { 1960return ; 1961 } 1962break ; 1963 } 1964case RPC_CMD_SET_TENSOR_HASH : { 1965rpc_msg_set_tensor_hash_req request ; 1966if (!recv_msg (sock ,& request ,sizeof (request ))) { 1967return ; 1968 } 1969rpc_msg_set_tensor_hash_rsp response ; 1970if (!server .set_tensor_hash (request ,response )) { 1971return ; 1972 } 1973if (!send_msg (sock ,& response ,sizeof (response ))) { 1974return ; 1975 } 1976break ; 1977 } 1978case RPC_CMD_INIT_TENSOR : { 1979rpc_msg_init_tensor_req request ; 1980if (!recv_msg (sock ,& request ,sizeof (request ))) { 1981return ; 1982 } 1983if (!server .init_tensor (request )) { 1984return ; 1985 } 1986break ; 1987 } 1988case RPC_CMD_GET_TENSOR : { 1989rpc_msg_get_tensor_req request ; 1990if (!recv_msg (sock ,& request ,sizeof (request ))) { 1991return ; 1992 } 1993 std::vector < uint8_t > response ; 1994if (!server .get_tensor (request ,response )) { 1995return ; 1996 } 1997if (!send_msg (sock ,response .data (),response .size ())) { 1998return ; 1999 } 2000break ; 2001 } 2002case RPC_CMD_COPY_TENSOR : { 2003rpc_msg_copy_tensor_req request ; 2004if (!recv_msg (sock ,& request ,sizeof (request ))) { 2005return ; 2006 } 2007rpc_msg_copy_tensor_rsp response ; 2008if (!server .copy_tensor (request ,response )) { 2009return ; 2010 } 2011if (!send_msg (sock ,& response ,sizeof (response ))) { 2012return ; 2013 } 2014break ; 2015 } 2016case RPC_CMD_GRAPH_COMPUTE : { 2017 std::vector < uint8_t > input ; 2018if (!recv_msg (sock ,input )) { 2019return ; 2020 } 2021if (!server .graph_compute (input )) { 2022return ; 2023 } 2024break ; 2025 } 2026case RPC_CMD_GRAPH_RECOMPUTE : { 2027rpc_msg_graph_recompute_req request ; 2028if (!recv_msg (sock ,& request ,sizeof (request ))) { 2029return ; 2030 } 2031if (!server .graph_recompute (request )) { 2032return ; 2033 } 2034break ; 2035 } 2036case RPC_CMD_GET_DEVICE_MEMORY : { 2037rpc_msg_get_device_memory_req request ; 2038if (!recv_msg (sock ,& request ,sizeof (request ))) { 2039return ; 2040 } 2041rpc_msg_get_device_memory_rsp response ; 2042if (!server .get_device_memory (request ,response )) { 2043return ; 2044 } 2045if (!send_msg (sock ,& response ,sizeof (response ))) { 2046return ; 2047 } 2048break ; 2049 } 2050default : { 2051GGML_LOG_ERROR ("Unknown command: %d\n" ,cmd ); 2052return ; 2053 } 2054 } 2055 } 2056} 2057 2058void ggml_backend_rpc_start_server (const char * endpoint ,const char * cache_dir , 2059size_t n_threads ,size_t n_devices ,ggml_backend_dev_t * devices ) { 2060if (n_devices == 0 || devices == nullptr ) { 2061fprintf (stderr ,"Invalid arguments to ggml_backend_rpc_start_server\n" ); 2062return ; 2063 } 2064 std::vector < ggml_backend_t > backends ; 2065printf ("Starting RPC server v%d.%d.%d\n" , 2066RPC_PROTO_MAJOR_VERSION , 2067RPC_PROTO_MINOR_VERSION , 2068RPC_PROTO_PATCH_VERSION ); 2069printf (" endpoint : %s\n" ,endpoint ); 2070printf (" local cache : %s\n" ,cache_dir ?cache_dir :"n/a" ); 2071printf ("Devices:\n" ); 2072for (size_t i = 0 ;i < n_devices ;i ++ ) { 2073auto dev = devices [i ]; 2074size_t free ,total ; 2075ggml_backend_dev_memory (dev ,& free ,& total ); 2076printf (" %s: %s (%zu MiB, %zu MiB free)\n" ,ggml_backend_dev_name (dev ),ggml_backend_dev_description (dev ), 2077total /1024 /1024 ,free /1024 /1024 ); 2078auto backend = ggml_backend_dev_init (dev ,nullptr ); 2079if (!backend ) { 2080fprintf (stderr ,"Failed to create backend for device %s\n" ,dev -> iface .get_name (dev )); 2081return ; 2082 } 2083backends .push_back (backend ); 2084ggml_backend_reg_t reg = dev ?ggml_backend_dev_backend_reg (dev ) :nullptr ; 2085if (reg ) { 2086auto ggml_backend_set_n_threads_fn = (ggml_backend_set_n_threads_t )ggml_backend_reg_get_proc_address (reg ,"ggml_backend_set_n_threads" ); 2087if (ggml_backend_set_n_threads_fn ) { 2088ggml_backend_set_n_threads_fn (backend ,n_threads ); 2089 } 2090 } 2091 } 2092 2093 std::string host ; 2094int port ; 2095if (!parse_endpoint (endpoint ,host ,port )) { 2096return ; 2097 } 2098 2099#ifdef GGML_RPC_RDMA 2100printf (" transport : TCP (RDMA auto-negotiate enabled)\n" ); 2101#else 2102printf (" transport : TCP\n" ); 2103#endif // GGML_RPC_RDMA 2104if (!rpc_transport_init ()) { 2105fprintf (stderr ,"Failed to initialize RPC transport\n" ); 2106return ; 2107 } 2108auto server_socket = socket_t::create_server (host .c_str (),port ); 2109if (server_socket == nullptr ) { 2110fprintf (stderr ,"Failed to create server socket\n" ); 2111return ; 2112 } 2113while (true) { 2114auto client_socket = server_socket -> accept (); 2115if (client_socket == nullptr ) { 2116fprintf (stderr ,"Failed to accept client connection\n" ); 2117return ; 2118 } 2119printf ("Accepted client connection\n" ); 2120fflush (stdout ); 2121rpc_serve_client (backends ,cache_dir ,client_socket ); 2122printf ("Client connection closed\n" ); 2123fflush (stdout ); 2124 } 2125rpc_transport_shutdown (); 2126for (auto backend :backends ) { 2127ggml_backend_free (backend ); 2128 } 2129} 2130 2131static const char * ggml_backend_rpc_device_get_name (ggml_backend_dev_t dev ) { 2132ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2133 2134return ctx -> name .c_str (); 2135} 2136 2137static const char * ggml_backend_rpc_device_get_description (ggml_backend_dev_t dev ) { 2138ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2139 2140return ctx -> description .c_str (); 2141} 2142 2143static void ggml_backend_rpc_device_get_memory (ggml_backend_dev_t dev ,size_t * free ,size_t * total ) { 2144ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2145 2146ggml_backend_rpc_get_device_memory (ctx -> endpoint .c_str (),ctx -> device ,free ,total ); 2147} 2148 2149static enum ggml_backend_dev_type ggml_backend_rpc_device_get_type (ggml_backend_dev_t dev ) { 2150// TODO: obtain value from the server 2151return GGML_BACKEND_DEVICE_TYPE_GPU ; 2152 2153GGML_UNUSED (dev ); 2154} 2155 2156static void ggml_backend_rpc_device_get_props (ggml_backend_dev_t dev ,struct ggml_backend_dev_props * props ) { 2157props -> name = ggml_backend_rpc_device_get_name (dev ); 2158props -> description = ggml_backend_rpc_device_get_description (dev ); 2159props -> type = ggml_backend_rpc_device_get_type (dev ); 2160ggml_backend_rpc_device_get_memory (dev ,& props -> memory_free ,& props -> memory_total ); 2161props -> caps = { 2162/* .async = */ true, 2163/* .host_buffer = */ false, 2164/* .buffer_from_host_ptr = */ false, 2165/* .events = */ true, 2166/* .mmap_support = */ true, 2167 }; 2168} 2169 2170static ggml_backend_t ggml_backend_rpc_device_init (ggml_backend_dev_t dev ,const char * params ) { 2171ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2172 2173return ggml_backend_rpc_init (ctx -> endpoint .c_str (),ctx -> device ); 2174 2175GGML_UNUSED (params ); 2176} 2177 2178static ggml_backend_buffer_type_t ggml_backend_rpc_device_get_buffer_type (ggml_backend_dev_t dev ) { 2179ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2180 2181return ggml_backend_rpc_buffer_type (ctx -> endpoint .c_str (),ctx -> device ); 2182 2183GGML_UNUSED (dev ); 2184} 2185 2186static bool ggml_backend_rpc_device_supports_op (ggml_backend_dev_t dev ,const struct ggml_tensor * op ) { 2187GGML_UNUSED (dev ); 2188GGML_UNUSED (op ); 2189//TODO: call the remote backend and cache the results 2190return true; 2191} 2192 2193static bool ggml_backend_rpc_device_supports_buft (ggml_backend_dev_t dev ,ggml_backend_buffer_type_t buft ) { 2194if (!buft || buft -> iface .get_name != ggml_backend_rpc_buffer_type_name ) { 2195return false; 2196 } 2197ggml_backend_rpc_buffer_type_context * buft_ctx = (ggml_backend_rpc_buffer_type_context * )buft -> context ; 2198ggml_backend_rpc_device_context * dev_ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2199return buft_ctx -> endpoint == dev_ctx -> endpoint && buft_ctx -> device == dev_ctx -> device ; 2200} 2201 2202static ggml_backend_event_t ggml_backend_rpc_device_event_new (ggml_backend_dev_t dev ) { 2203ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2204auto dispatcher = get_dispatcher (ctx -> endpoint ); 2205return dispatcher -> event_new (dev ); 2206} 2207 2208static void ggml_backend_rpc_device_event_free (ggml_backend_dev_t dev ,ggml_backend_event_t event ) { 2209ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2210auto dispatcher = get_dispatcher (ctx -> endpoint ); 2211dispatcher -> event_free (event ); 2212} 2213 2214static void ggml_backend_rpc_device_event_synchronize (ggml_backend_dev_t dev ,ggml_backend_event_t event ) { 2215ggml_backend_rpc_device_context * ctx = (ggml_backend_rpc_device_context * )dev -> context ; 2216auto dispatcher = get_dispatcher (ctx -> endpoint ); 2217dispatcher -> event_synchronize (event ); 2218} 2219 2220static const struct ggml_backend_device_i ggml_backend_rpc_device_i = { 2221/* .get_name = */ ggml_backend_rpc_device_get_name , 2222/* .get_description = */ ggml_backend_rpc_device_get_description , 2223/* .get_memory = */ ggml_backend_rpc_device_get_memory , 2224/* .get_type = */ ggml_backend_rpc_device_get_type , 2225/* .get_props = */ ggml_backend_rpc_device_get_props , 2226/* .init_backend = */ ggml_backend_rpc_device_init , 2227/* .get_buffer_type = */ ggml_backend_rpc_device_get_buffer_type , 2228/* .get_host_buffer_type = */ NULL , 2229/* .buffer_from_host_ptr = */ NULL , 2230/* .supports_op = */ ggml_backend_rpc_device_supports_op , 2231/* .supports_buft = */ ggml_backend_rpc_device_supports_buft , 2232/* .offload_op = */ NULL , 2233/* .event_new = */ ggml_backend_rpc_device_event_new , 2234/* .event_free = */ ggml_backend_rpc_device_event_free , 2235/* .event_synchronize = */ ggml_backend_rpc_device_event_synchronize , 2236}; 2237 2238// backend reg interface 2239 2240struct ggml_backend_rpc_reg_context { 2241 std::string name ; 2242 std::vector < ggml_backend_dev_t > devices ; 2243}; 2244 2245static const char * ggml_backend_rpc_reg_get_name (ggml_backend_reg_t reg ) { 2246ggml_backend_rpc_reg_context * ctx = (ggml_backend_rpc_reg_context * )reg -> context ; 2247return ctx ?ctx -> name .c_str () :"RPC" ; 2248} 2249 2250static size_t ggml_backend_rpc_reg_get_device_count (ggml_backend_reg_t reg ) { 2251ggml_backend_rpc_reg_context * ctx = (ggml_backend_rpc_reg_context * )reg -> context ; 2252return ctx ?ctx -> devices .size () :0 ; 2253} 2254 2255static ggml_backend_dev_t ggml_backend_rpc_reg_get_device (ggml_backend_reg_t reg ,size_t index ) { 2256ggml_backend_rpc_reg_context * ctx = (ggml_backend_rpc_reg_context * )reg -> context ; 2257if (ctx == nullptr ) { 2258GGML_ABORT ("The RPC backend does not have enumerated devices - use ggml_backend_rpc_add_server instead" ); 2259 }else { 2260GGML_ASSERT (index < ctx -> devices .size ()); 2261return ctx -> devices [index ]; 2262 } 2263} 2264 2265static void * ggml_backend_rpc_get_proc_address (ggml_backend_reg_t reg ,const char * name ) { 2266if (std::strcmp (name ,"ggml_backend_rpc_add_server" )== 0 ) { 2267return (void * )ggml_backend_rpc_add_server ; 2268 } 2269if (std::strcmp (name ,"ggml_backend_rpc_start_server" )== 0 ) { 2270return (void * )ggml_backend_rpc_start_server ; 2271 } 2272return NULL ; 2273 2274GGML_UNUSED (reg ); 2275} 2276 2277static const struct ggml_backend_reg_i ggml_backend_rpc_reg_i = { 2278/* .get_name = */ ggml_backend_rpc_reg_get_name , 2279/* .get_device_count = */ ggml_backend_rpc_reg_get_device_count , 2280/* .get_device = */ ggml_backend_rpc_reg_get_device , 2281/* .get_proc_address = */ ggml_backend_rpc_get_proc_address , 2282}; 2283 2284ggml_backend_reg_t ggml_backend_rpc_reg (void ) { 2285static struct ggml_backend_reg ggml_backend_rpc_reg = { 2286/* .api_version = */ GGML_BACKEND_API_VERSION , 2287/* .iface = */ ggml_backend_rpc_reg_i , 2288/* .context = */ NULL , 2289 }; 2290 2291return & ggml_backend_rpc_reg ; 2292} 2293 2294static uint32_t ggml_backend_rpc_get_device_count (const char * endpoint ) { 2295auto dispatcher = get_dispatcher (endpoint ); 2296rpc_msg_device_count_rsp response ; 2297dispatcher -> send (RPC_CMD_DEVICE_COUNT ,nullptr ,0 ,& response ,sizeof (response )); 2298return response .device_count ; 2299} 2300 2301static const ggml_backend_reg_i ggml_backend_rpc_reg_interface = { 2302/* .get_name = */ ggml_backend_rpc_reg_get_name , 2303/* .get_device_count = */ ggml_backend_rpc_reg_get_device_count , 2304/* .get_device = */ ggml_backend_rpc_reg_get_device , 2305/* .get_proc_address = */ ggml_backend_rpc_get_proc_address , 2306}; 2307 2308ggml_backend_reg_t ggml_backend_rpc_add_server (const char * endpoint ) { 2309static std::unordered_map < std::string ,ggml_backend_reg_t > reg_map ; 2310static std::mutex mutex ; 2311static uint32_t dev_id = 0 ; 2312 std::lock_guard < std::mutex > lock (mutex ); 2313if (reg_map .find (endpoint )!= reg_map .end ()) { 2314return reg_map [endpoint ]; 2315 } 2316uint32_t dev_count = ggml_backend_rpc_get_device_count (endpoint ); 2317if (dev_count == 0 ) { 2318return nullptr ; 2319 } 2320ggml_backend_rpc_reg_context * ctx = new ggml_backend_rpc_reg_context ; 2321ctx -> name = "RPC[" + std::string (endpoint )+ "]" ; 2322for (uint32_t ind = 0 ;ind < dev_count ;ind ++ ) { 2323 std::string dev_name = "RPC" + std::to_string (dev_id ); 2324 std::string dev_desc = std::string (endpoint ); 2325ggml_backend_rpc_device_context * dev_ctx = new ggml_backend_rpc_device_context { 2326/* .endpoint = */ endpoint , 2327/* .device = */ ind , 2328/* .name = */ dev_name , 2329/* .description = */ dev_desc , 2330/* .last_graph_uid = */ 0 , 2331 }; 2332 2333ggml_backend_dev_t dev = new ggml_backend_device { 2334/* .iface = */ ggml_backend_rpc_device_i , 2335/* .reg = */ ggml_backend_rpc_reg (), 2336/* .context = */ dev_ctx , 2337 }; 2338ctx -> devices .push_back (dev ); 2339dev_id ++ ; 2340 } 2341ggml_backend_reg_t reg = new ggml_backend_reg { 2342/* .api_version = */ GGML_BACKEND_API_VERSION , 2343/* .iface = */ ggml_backend_rpc_reg_interface , 2344/* .context = */ ctx 2345 }; 2346reg_map [endpoint ]= reg ; 2347return reg ; 2348} 2349 2350 2351GGML_BACKEND_DL_IMPL (ggml_backend_rpc_reg )