char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
09294365a
char/aliceai-t5-moe
1#include "virtgpu.h" 2#include "ggml-remoting.h" 3 4#include <stdio.h> 5#include <unistd.h> 6 7#include <cassert> 8#include <cerrno> 9#include <cstdlib> 10 11static virt_gpu_result_t virtgpu_open_device (virtgpu * gpu ,const drmDevicePtr dev ); 12static virt_gpu_result_t virtgpu_open (virtgpu * gpu ); 13 14static virt_gpu_result_t virtgpu_init_capset (virtgpu * gpu ); 15static virt_gpu_result_t virtgpu_init_context (virtgpu * gpu ); 16 17static int virtgpu_ioctl_context_init (virtgpu * gpu ,virgl_renderer_capset capset_id ); 18static int virtgpu_ioctl_get_caps (virtgpu * gpu , 19virgl_renderer_capset id , 20uint32_t version , 21void * capset , 22size_t capset_size ); 23static uint64_t virtgpu_ioctl_getparam (virtgpu * gpu ,uint64_t param ); 24static void virtgpu_init_renderer_info (virtgpu * gpu ); 25 26static void log_call_duration (long long call_duration_ns ,const char * name ); 27 28const uint64_t APIR_HANDSHAKE_MAX_WAIT_MS = 2 * 1000 ;// 2s 29const uint64_t APIR_LOADLIBRARY_MAX_WAIT_MS = 60 * 1000 ;// 60s 30 31static int virtgpu_handshake (virtgpu * gpu ) { 32apir_encoder * encoder ; 33apir_decoder * decoder ; 34 35encoder = remote_call_prepare (gpu ,APIR_COMMAND_TYPE_HANDSHAKE ,0 ); 36if (!encoder ) { 37GGML_ABORT (GGML_VIRTGPU "%s: failed to prepare the remote call encoder" ,__func__ ); 38return 1 ; 39 } 40 41/* write handshake props */ 42 43uint32_t guest_major = APIR_PROTOCOL_MAJOR ; 44uint32_t guest_minor = APIR_PROTOCOL_MINOR ; 45apir_encode_uint32_t (encoder ,& guest_major ); 46apir_encode_uint32_t (encoder ,& guest_minor ); 47 48/* *** */ 49 50uint32_t ret_magic ; 51long long call_duration_ns ; 52ret_magic = remote_call (gpu ,encoder ,& decoder ,APIR_HANDSHAKE_MAX_WAIT_MS ,& call_duration_ns ); 53log_call_duration (call_duration_ns ,"API Remoting handshake" ); 54 55if (!decoder ) { 56GGML_ABORT (GGML_VIRTGPU 57"%s: failed to initiate the communication with the virglrenderer library. " 58"Most likely, the wrong virglrenderer library was loaded in the hypervisor." , 59__func__ ); 60return 1 ; 61 } 62 63/* read handshake return values */ 64 65uint32_t host_major ; 66uint32_t host_minor ; 67 68if (ret_magic != APIR_HANDSHAKE_MAGIC ) { 69GGML_ABORT (GGML_VIRTGPU "%s: handshake with the virglrenderer failed (code=%d | %s)" ,__func__ ,ret_magic , 70apir_backend_initialize_error (ret_magic )); 71 }else { 72apir_decode_uint32_t (decoder ,& host_major ); 73apir_decode_uint32_t (decoder ,& host_minor ); 74 } 75 76remote_call_finish (gpu ,encoder ,decoder ); 77 78if (ret_magic != APIR_HANDSHAKE_MAGIC ) { 79return 1 ; 80 } 81 82GGML_LOG_INFO (GGML_VIRTGPU "%s: Guest is running with %u.%u\n" ,__func__ ,guest_major ,guest_minor ); 83GGML_LOG_INFO (GGML_VIRTGPU "%s: Host is running with %u.%u\n" ,__func__ ,host_major ,host_minor ); 84 85if (guest_major != host_major ) { 86GGML_LOG_ERROR (GGML_VIRTGPU "Host major (%d) and guest major (%d) version differ\n" ,host_major ,guest_major ); 87 }else if (guest_minor != host_minor ) { 88GGML_LOG_WARN (GGML_VIRTGPU "Host minor (%d) and guest minor (%d) version differ\n" ,host_minor ,guest_minor ); 89 } 90 91return 0 ; 92} 93 94static ApirLoadLibraryReturnCode virtgpu_load_library (virtgpu * gpu ) { 95apir_encoder * encoder ; 96apir_decoder * decoder ; 97ApirLoadLibraryReturnCode ret ; 98 99encoder = remote_call_prepare (gpu ,APIR_COMMAND_TYPE_LOADLIBRARY ,0 ); 100if (!encoder ) { 101GGML_ABORT (GGML_VIRTGPU "%s: hypercall error: failed to prepare the API Remoting command encoder" ,__func__ ); 102return APIR_LOAD_LIBRARY_HYPERCALL_INITIALIZATION_ERROR ; 103 } 104 105long long call_duration_ns ; 106 107ret = (ApirLoadLibraryReturnCode )remote_call (gpu ,encoder ,& decoder ,APIR_LOADLIBRARY_MAX_WAIT_MS , 108& call_duration_ns ); 109log_call_duration (call_duration_ns ,"API Remoting LoadLibrary" ); 110 111if (!decoder ) { 112GGML_ABORT (GGML_VIRTGPU "%s: hypercall error: failed to trigger the API Remoting hypercall.\n" ,__func__ ); 113return APIR_LOAD_LIBRARY_HYPERCALL_INITIALIZATION_ERROR ; 114 } 115 116remote_call_finish (gpu ,encoder ,decoder ); 117 118if (ret == APIR_LOAD_LIBRARY_SUCCESS ) { 119GGML_LOG_INFO (GGML_VIRTGPU "The API Remoting backend was successfully loaded and initialized\n" ); 120 121return ret ; 122 } 123 124// something wrong happened, find out what. 125if (ret < APIR_LOAD_LIBRARY_INIT_BASE_INDEX ) { 126if (ret == APIR_LOAD_LIBRARY_ENV_VAR_MISSING ) { 127GGML_ABORT (GGML_VIRTGPU 128"%s: virglrenderer could not open the API Remoting backend library, " 129"some environment variables are missing. " 130"Make sure virglrenderer is correctly configured by the hypervisor. (%s)" , 131__func__ ,apir_load_library_error (ret )); 132 }else if (ret == APIR_LOAD_LIBRARY_CANNOT_OPEN ) { 133GGML_ABORT (GGML_VIRTGPU 134"%s: virglrenderer could not open the API Remoting backend library. " 135"Make sure virglrenderer is correctly configured by the hypervisor. (%s)" , 136__func__ ,apir_load_library_error (ret )); 137 }else if (ret == APIR_LOAD_LIBRARY_ENV_VAR_MISSING ) { 138GGML_ABORT (GGML_VIRTGPU 139"%s: could not load the backend library, some symbols are missing. " 140"Make sure virglrenderer is correctly configured by the hypervisor. (%s) " , 141__func__ ,apir_load_library_error (ret )); 142 }else { 143GGML_ABORT (GGML_VIRTGPU "%s: virglrenderer could not load the API Remoting backend library. (%s - code %d)" , 144__func__ ,apir_load_library_error (ret ),ret ); 145 } 146return ret ; 147 } 148 149GGML_LOG_INFO (GGML_VIRTGPU "%s: virglrenderer successfully loaded the API Remoting backend library.\n" ,__func__ ); 150 151ApirLoadLibraryReturnCode apir_ret = (ApirLoadLibraryReturnCode ) (ret - APIR_LOAD_LIBRARY_INIT_BASE_INDEX ); 152 153if (apir_ret == APIR_LOAD_LIBRARY_CANNOT_OPEN ) { 154GGML_ABORT (GGML_VIRTGPU 155"%s: the API Remoting backend library couldn't load the GGML backend library. " 156"Make sure virglrenderer is correctly configured by the hypervisor. (%s)" , 157__func__ ,apir_load_library_error (apir_ret )); 158 }else if (apir_ret == APIR_LOAD_LIBRARY_SYMBOL_MISSING ) { 159GGML_ABORT ( 160GGML_VIRTGPU 161"%s: the API Remoting backend library couldn't load the GGML backend library, some symbols are missing. " 162"Make sure virglrenderer is correctly configured by the hypervisor. (%s)" , 163__func__ ,apir_load_library_error (apir_ret )); 164 }else if (apir_ret < APIR_LOAD_LIBRARY_INIT_BASE_INDEX ) { 165GGML_ABORT (GGML_VIRTGPU 166"%s: the API Remoting backend library couldn't load the GGML backend library: apir code=%d | %s)" , 167__func__ ,apir_ret ,apir_load_library_error (apir_ret )); 168 }else { 169uint32_t lib_ret = apir_ret - APIR_LOAD_LIBRARY_INIT_BASE_INDEX ; 170GGML_ABORT (GGML_VIRTGPU 171"%s: the API Remoting backend library failed to initialize its backend library: apir code=%d)" , 172__func__ ,lib_ret ); 173 } 174return ret ; 175} 176 177virtgpu * create_virtgpu () { 178virtgpu * gpu = new virtgpu (); 179 180gpu -> use_apir_capset = getenv ("GGML_REMOTING_USE_APIR_CAPSET" )!= nullptr ; 181util_sparse_array_init (& gpu -> shmem_array ,sizeof (virtgpu_shmem ),1024 ); 182 183// Initialize mutex to protect shared data_shmem buffer 184if (mtx_init (& gpu -> data_shmem_mutex ,mtx_plain )!= thrd_success ) { 185delete gpu ; 186GGML_ABORT (GGML_VIRTGPU "%s: failed to initialize data_shmem mutex" ,__func__ ); 187return NULL ; 188 } 189 190if (virtgpu_open (gpu )!= APIR_SUCCESS ) { 191GGML_LOG_ERROR (GGML_VIRTGPU "%s: failed to open the virtgpu device\n" ,__func__ ); 192return NULL ; 193 } 194 195if (virtgpu_init_capset (gpu )!= APIR_SUCCESS ) { 196if (gpu -> use_apir_capset ) { 197GGML_ABORT (GGML_VIRTGPU 198"%s: failed to initialize the virtgpu APIR capset. Make sure that the virglrenderer library " 199"supports it." , 200__func__ ); 201 }else { 202GGML_ABORT (GGML_VIRTGPU "%s: failed to initialize the virtgpu Venus capset" ,__func__ ); 203 } 204return NULL ; 205 } 206 207if (virtgpu_init_context (gpu )!= APIR_SUCCESS ) { 208GGML_ABORT (GGML_VIRTGPU "%s: failed to initialize the GPU context" ,__func__ ); 209return NULL ; 210 } 211 212if (virtgpu_shmem_create (gpu ,SHMEM_REPLY_SIZE ,& gpu -> reply_shmem )) { 213GGML_ABORT (GGML_VIRTGPU "%s: failed to create the shared reply memory pages" ,__func__ ); 214return NULL ; 215 } 216 217if (virtgpu_shmem_create (gpu ,SHMEM_DATA_SIZE ,& gpu -> data_shmem )) { 218GGML_ABORT (GGML_VIRTGPU "%s: failed to create the shared data memory pages" ,__func__ ); 219return NULL ; 220 } 221 222if (virtgpu_handshake (gpu )) { 223GGML_ABORT (GGML_VIRTGPU "%s: failed to handshake with the virglrenderer library" ,__func__ ); 224return NULL ; 225 } 226 227if (virtgpu_load_library (gpu )!= APIR_LOAD_LIBRARY_SUCCESS ) { 228GGML_ABORT (GGML_VIRTGPU "%s: failed to load the backend library" ,__func__ ); 229return NULL ; 230 } 231 232return gpu ; 233} 234 235static virt_gpu_result_t virtgpu_open (virtgpu * gpu ) { 236drmDevicePtr devs [8 ]; 237int count = drmGetDevices2 (0 ,devs ,ARRAY_SIZE (devs )); 238if (count < 0 ) { 239GGML_LOG_ERROR (GGML_VIRTGPU "%s: failed to enumerate DRM devices\n" ,__func__ ); 240return APIR_ERROR_INITIALIZATION_FAILED ; 241 } 242 243virt_gpu_result_t result = APIR_ERROR_INITIALIZATION_FAILED ; 244for (int i = 0 ;i < count ;i ++ ) { 245result = virtgpu_open_device (gpu ,devs [i ]); 246if (result == APIR_SUCCESS ) { 247break ; 248 } 249 } 250 251drmFreeDevices (devs ,count ); 252 253return result ; 254} 255 256static virt_gpu_result_t virtgpu_open_device (virtgpu * gpu ,const drmDevicePtr dev ) { 257const char * node_path = dev -> nodes [DRM_NODE_RENDER ]; 258 259int fd = open (node_path ,O_RDWR |O_CLOEXEC ); 260if (fd < 0 ) { 261GGML_ABORT (GGML_VIRTGPU "%s: failed to open %s" ,__func__ ,node_path ); 262return APIR_ERROR_INITIALIZATION_FAILED ; 263 } 264 265drmVersionPtr version = drmGetVersion (fd ); 266if (!version || strcmp (version -> name ,"virtio_gpu" )|| version -> version_major != 0 ) { 267if (version ) { 268GGML_LOG_ERROR (GGML_VIRTGPU "%s: unknown DRM driver %s version %d\n" ,__func__ ,version -> name , 269version -> version_major ); 270 }else { 271GGML_LOG_ERROR (GGML_VIRTGPU "%s: failed to get DRM driver version\n" ,__func__ ); 272 } 273 274if (version ) { 275drmFreeVersion (version ); 276 } 277close (fd ); 278return APIR_ERROR_INITIALIZATION_FAILED ; 279 } 280 281gpu -> fd = fd ; 282 283drmFreeVersion (version ); 284 285GGML_LOG_INFO (GGML_VIRTGPU "using DRM device %s\n" ,node_path ); 286 287return APIR_SUCCESS ; 288} 289 290static virt_gpu_result_t virtgpu_init_context (virtgpu * gpu ) { 291assert (!gpu -> capset .version ); 292const int ret = virtgpu_ioctl_context_init (gpu ,gpu -> capset .id ); 293if (ret ) { 294GGML_LOG_ERROR (GGML_VIRTGPU "%s: failed to initialize context: %s\n" ,__func__ ,strerror (errno )); 295return APIR_ERROR_INITIALIZATION_FAILED ; 296 } 297 298return APIR_SUCCESS ; 299} 300 301static virt_gpu_result_t virtgpu_init_capset (virtgpu * gpu ) { 302if (gpu -> use_apir_capset ) { 303GGML_LOG_INFO (GGML_VIRTGPU "Using the APIR capset\n" ); 304gpu -> capset .id = VIRTGPU_DRM_CAPSET_APIR ; 305 }else { 306GGML_LOG_INFO (GGML_VIRTGPU "Using the Venus capset\n" ); 307gpu -> capset .id = VIRTGPU_DRM_CAPSET_VENUS ; 308 } 309gpu -> capset .version = 0 ; 310 311int ret = 312virtgpu_ioctl_get_caps (gpu ,gpu -> capset .id ,gpu -> capset .version ,& gpu -> capset .data ,sizeof (gpu -> capset .data )); 313 314if (ret ) { 315GGML_LOG_ERROR (GGML_VIRTGPU "%s: failed to get APIR v%d capset: %s\n" ,__func__ ,gpu -> capset .version , 316strerror (errno )); 317return APIR_ERROR_INITIALIZATION_FAILED ; 318 } 319 320assert (gpu -> capset .data .supports_blob_resources ); 321 322return APIR_SUCCESS ; 323} 324 325static int virtgpu_ioctl_context_init (virtgpu * gpu ,virgl_renderer_capset capset_id ) { 326drm_virtgpu_context_set_param ctx_set_params [3 ]= { 327 { 328 .param = VIRTGPU_CONTEXT_PARAM_CAPSET_ID , 329 .value = capset_id , 330 }, 331 { 332 .param = VIRTGPU_CONTEXT_PARAM_NUM_RINGS , 333 .value = 1 , 334 }, 335 { 336 .param = VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK , 337 .value = 0 ,/* don't generate drm_events on fence signaling */ 338 }, 339 }; 340 341drm_virtgpu_context_init args = { 342 .num_params = ARRAY_SIZE (ctx_set_params ), 343 .pad = 0 , 344 .ctx_set_params = (uintptr_t )& ctx_set_params , 345 }; 346 347return virtgpu_ioctl (gpu ,DRM_IOCTL_VIRTGPU_CONTEXT_INIT ,& args ); 348} 349 350static int virtgpu_ioctl_get_caps (virtgpu * gpu , 351virgl_renderer_capset id , 352uint32_t version , 353void * capset , 354size_t capset_size ) { 355drm_virtgpu_get_caps args = { 356 .cap_set_id = id , 357 .cap_set_ver = version , 358 .addr = (uintptr_t )capset , 359 .size = (__u32 )capset_size , 360 .pad = 0 , 361 }; 362 363return virtgpu_ioctl (gpu ,DRM_IOCTL_VIRTGPU_GET_CAPS ,& args ); 364} 365 366static uint64_t virtgpu_ioctl_getparam (virtgpu * gpu ,uint64_t param ) { 367/* val must be zeroed because kernel only writes the lower 32 bits */ 368uint64_t val = 0 ; 369drm_virtgpu_getparam args = { 370 .param = param , 371 .value = (uintptr_t )& val , 372 }; 373 374const int ret = virtgpu_ioctl (gpu ,DRM_IOCTL_VIRTGPU_GETPARAM ,& args ); 375return ret ?0 :val ; 376} 377 378apir_encoder * remote_call_prepare (virtgpu * gpu ,ApirCommandType apir_cmd_type ,int32_t cmd_flags ) { 379/* 380* Prepare the command encoder and its buffer 381*/ 382 383 thread_localchar encoder_buffer [4096 ]; 384 385 thread_localapir_encoder enc ; 386enc = { 387 .cur = encoder_buffer , 388 .start = encoder_buffer , 389 .end = encoder_buffer + sizeof (encoder_buffer ), 390 .fatal = false, 391 }; 392 393/* 394* Fill the command encoder with the common args: 395* - cmd_type (int32_t) 396* - cmd_flags (int32_t) 397* - reply res id (uint32_t) 398*/ 399 400int32_t cmd_type = apir_cmd_type ; 401 402// for testing during the hypervisor transition 403if (!gpu -> use_apir_capset ) { 404cmd_type += VENUS_COMMAND_TYPE_LENGTH ; 405 } 406apir_encode_int32_t (& enc ,& cmd_type ); 407apir_encode_int32_t (& enc ,& cmd_flags ); 408 409uint32_t reply_res_id = gpu -> reply_shmem .res_id ; 410apir_encode_uint32_t (& enc ,& reply_res_id ); 411 412return & enc ; 413} 414 415void remote_call_finish (virtgpu * gpu ,apir_encoder * enc ,apir_decoder * dec ) { 416UNUSED (gpu ); 417 418if (!enc ) { 419GGML_ABORT (GGML_VIRTGPU "%s: Invalid (null) encoder" ,__func__ ); 420 } 421 422if (!dec ) { 423GGML_ABORT (GGML_VIRTGPU "%s: Invalid (null) decoder" ,__func__ ); 424 } 425 426if (apir_encoder_get_fatal (enc )) { 427GGML_LOG_ERROR (GGML_VIRTGPU "%s: Failed to encode the output parameters." ,__func__ ); 428 } 429 430if (apir_decoder_get_fatal (dec )) { 431GGML_LOG_ERROR (GGML_VIRTGPU "%s: Failed to decode the input parameters." ,__func__ ); 432 } 433} 434 435uint32_t remote_call (virtgpu * gpu , 436apir_encoder * encoder , 437apir_decoder ** decoder , 438float max_wait_ms , 439long long * call_duration_ns ) { 440/* 441* Prepare the reply notification pointer 442*/ 443 444volatile std::atomic_uint * atomic_reply_notif = (volatile std::atomic_uint * )gpu -> reply_shmem .mmap_ptr ; 445* atomic_reply_notif = 0 ; 446 447/* 448* Trigger the execbuf ioctl 449*/ 450 451drm_virtgpu_execbuffer args = { 452 .flags = VIRTGPU_EXECBUF_RING_IDX , 453 .size = (uint32_t ) (encoder -> cur - encoder -> start ), 454 .command = (uintptr_t )encoder -> start , 455 456 .bo_handles = 0 , 457 .num_bo_handles = 0 , 458 459 .fence_fd = 0 , 460 .ring_idx = 0 , 461 .syncobj_stride = 0 , 462 .num_in_syncobjs = 0 , 463 .num_out_syncobjs = 0 , 464 .in_syncobjs = 0 , 465 .out_syncobjs = 0 , 466 }; 467 468* decoder = NULL ; 469 470int ret = drmIoctl (gpu -> fd ,DRM_IOCTL_VIRTGPU_EXECBUFFER ,& args ); 471 472if (ret != 0 ) { 473GGML_ABORT (GGML_VIRTGPU "%s: the virtgpu EXECBUFFER ioctl failed (%d)" ,__func__ ,ret ); 474 } 475 476/* 477* Wait for the response notification 478*/ 479timer_data wait_host_reply_timer = {0 ,0 ,0 }; 480 481start_timer (& wait_host_reply_timer ); 482 483timespec ts_start ,ts_end ; 484clock_gettime (CLOCK_MONOTONIC ,& ts_start ); 485long long start_time = (long long )ts_start .tv_sec * 1000000000LL + ts_start .tv_nsec ; 486 487bool timedout = false; 488uint32_t notif_value = 0 ; 489while (true) { 490notif_value = std::atomic_load_explicit (atomic_reply_notif , std::memory_order_acquire ); 491 492if (notif_value != 0 ) { 493break ; 494 } 495 496int64_t base_sleep_us = 15 ; 497 498os_time_sleep (base_sleep_us ); 499 500if (max_wait_ms ) { 501clock_gettime (CLOCK_MONOTONIC ,& ts_end ); 502long long end_time = (long long )ts_end .tv_sec * 1000000000LL + ts_end .tv_nsec ; 503float duration_ms = (end_time - start_time ) /1000000 ; 504 505if (duration_ms > max_wait_ms ) { 506timedout = true; 507break ; 508 } 509 } 510 } 511 512if (call_duration_ns ) { 513* call_duration_ns = stop_timer (& wait_host_reply_timer ); 514 } 515 516if (max_wait_ms && timedout ) { 517GGML_LOG_ERROR (GGML_VIRTGPU "%s: timed out waiting for the host answer...\n" ,__func__ ); 518return APIR_FORWARD_TIMEOUT ; 519 } 520 521/* 522* Prepare the decoder 523*/ 524static apir_decoder response_dec ; 525response_dec .cur = (char * )gpu -> reply_shmem .mmap_ptr + sizeof (* atomic_reply_notif ); 526response_dec .end = (char * )gpu -> reply_shmem .mmap_ptr + gpu -> reply_shmem .mmap_size ; 527* decoder = & response_dec ; 528 529// extract the actual return value from the notif flag 530uint32_t returned_value = notif_value - 1 ; 531return returned_value ; 532} 533 534static void log_call_duration (long long call_duration_ns ,const char * name ) { 535double call_duration_ms = (double )call_duration_ns /1e6 ;// 1 millisecond = 1e6 nanoseconds 536double call_duration_s = (double )call_duration_ns /1e9 ;// 1 second = 1e9 nanoseconds 537 538if (call_duration_s > 1 ) { 539GGML_LOG_INFO (GGML_VIRTGPU "waited %.2fs for the %s host reply...\n" ,call_duration_s ,name ); 540 }else if (call_duration_ms > 1 ) { 541GGML_LOG_INFO (GGML_VIRTGPU "waited %.2fms for the %s host reply...\n" ,call_duration_ms ,name ); 542 }else { 543GGML_LOG_INFO (GGML_VIRTGPU "waited %lldns for the %s host reply...\n" ,call_duration_ns ,name ); 544 } 545}