• qemu-kvm下的vcuda虚拟化



    背景:
     当前AI和大模型火热,对算力的需求越来越高,如何高效的利用算力资源问题被凸显出来了。

    目标:
     在虚拟化场景下,单张显卡的算力能同时被多个虚拟机调度使用。

    技术:
     cuda虚拟化,一张显卡的cuda算力能同时被多个虚拟机使用。

     基于qemu-kvm虚拟化,在虚拟机内实现一个 vcuda-pci 设备,进行 guest 和 host 之间的数据交互;

      A  guest侧:编写设备驱动,实现 file_ops 相关的接口,承接guest侧应用的 cuda api 请求,支持Linux、Windows虚拟机;
      B  host侧:接收 guest 过来的api接口及参数数据,将参数重新组装,然后调用物理显卡的cuda api,并将所需结果返回给guest侧;

    核心点:整体流程的时延,cuda api的支持个数。

    ##########################################################################

    利用中秋+国庆双节的时间,整了个demo出来

    qemu侧(基于6.2.0):

    命令行添加如下参数:

    -device virtio-vcuda-pci

    host侧:

    host上有一块1660s的显卡,并且安装了cuda 12.2

    启动虚拟机:

    /mnt/qemu-debug/bin/qemu-system-x86_64 -enable-kvm -vga std -m 4096 -smp 4 -cpu host -net nic,model=e1000 -net user -hda /home/ubuntu2004.img -vnc 0.0.0.0:0 -device virtio-vcuda-pci

    guest侧(只设配了Linux虚拟机,Windows代码移过去就行,都是对device的操作):

    可以看到guest虚拟机内是没有显卡的:

    虚拟机内的vcuda-pci设备:

    加载驱动并生成动态库:

        libcudart.so.12.2.140

    测试demo程序 test123.c :

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. int main()
    7. {
    8. int a;
    9. int count;
    10. //char *name = (char *)malloc(100);
    11. char name[100];
    12. int len = 50;
    13. CUresult cuinit = cuInit(0);
    14. CUcontext pctx;
    15. cuCtxCreate(&pctx, 0, 0);
    16. const char *err_str;
    17. cuGetErrorName(cuinit, &err_str);
    18. printf("----err_name = %s----\n", err_str);
    19. cuGetErrorString(cuinit, &err_str);
    20. printf("----err_str = %s----\n", err_str);
    21. cuDriverGetVersion(&a);
    22. printf("version = %d------\n", a);
    23. CUdevice device;
    24. cuDeviceGet(&device, 0);
    25. printf("device = %d---\n", device);
    26. cuDeviceGetCount(&count);
    27. printf("count = %d------\n", count);
    28. cuDeviceGetName(name, len, device);
    29. printf("name = %s------\n", name);
    30. CUuuid *uuid = malloc(sizeof(CUuuid));
    31. cuDeviceGetUuid(uuid, device);
    32. printf("Uuid = ");
    33. for (int j = 0; j < sizeof(CUuuid); j++) {
    34. printf("%02hhX", uuid->bytes[j]);
    35. }
    36. printf("\n");
    37. char luid[50];
    38. unsigned int mask;
    39. cuDeviceGetLuid(luid, &mask, device);
    40. printf("----luid=%s---mask=%d----\n", luid, mask);
    41. size_t mem;
    42. cuDeviceTotalMem(&mem, device);
    43. printf("TotalMem = %ld------\n", mem);
    44. int pi;
    45. //CUdevice_attribute attrib = CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT;
    46. CUdevice_attribute attrib = CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR;
    47. cuDeviceGetAttribute(&pi, attrib, device);
    48. printf("---pi = %d--\n", pi);
    49. printf("CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR = %d---\n", CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR);
    50. CUdeviceptr dptr;
    51. size_t memalloc = 225002496;
    52. cuMemAlloc(&dptr, memalloc);
    53. printf("---cuda mem alloc = %lld----\n", dptr);
    54. cuCtxDestroy(pctx);
    55. return 0;
    56. }
    57. // gcc -o test123 test123.c -I /usr/local/cuda/include/ -lm ./libcudart.so.12.2.140

    运行效果:

    可以看到在虚拟机内调用到了host上的显卡,实现了cuda虚拟化的效果


    TODO:
     适配更多的cuda api,算力隔离,QoS,灵活调度策略。。。

  • 相关阅读:
    一文看懂ELK日志查看安装配置(超详细)
    Facebook个人主页和公共主页的区别
    Git常见的面试题
    ToBeWritten之理解攻击者
    项目测试一半,需求要变更,测试人员怎么办?
    王道计网:数据链路层
    【文本分类】《融合注意力和剪裁机制的通用文本分类模型》
    Matlab深度学习实战一:LeNe-5图像分类篇MNIST数据集分十类且matlab提供模型框架全网为唯一详细操作流程
    Android-树形选择列表
    缓存预热Springboot定时任务
  • 原文地址:https://blog.csdn.net/u014022631/article/details/133080000