Bootstrap

GPU虚拟化

在嵌入式虚拟化中,常遇到能移植hypervisor,能启动虚拟机,如果要显示图形界面有两种方案:
    一是GPU设备透传,虚拟机加载原生图形栈
    二是GPU虚拟化,其中GPU虚拟化又分为硬件辅助的GPU虚拟化和软件的GPU虚拟化
    方案一不属于严格意义上的GPU虚拟化,本文主要分析方案二GPU虚拟化。
对比GPU透传GPU虚拟化
功能一个GPU仅支持一个OS一个GPU支持多OS显示
性能接近原生弱于原生

1. 概述

1.1 GPU子系统分层

GPU典型架构

GPU主要用于通用计算和图形渲染。上图GPU子系统抽象了几层概念:
      应用程序:调用图形API,如OpenGLES,Vulkan
      底层库:图形用户态驱动,一般为GPU厂商闭源实现
      内核和硬件:包括GPU硬件驱动,最底层为GPU硬件

1.2 GPU虚拟化需求

多虚拟机对GPU资源共享的需求,应用场景如:
    多屏车机(IVI/Cluster共用GPU)
    本地桌面虚拟机(Vmvare,Virtualbox,Qemu-kvm)
    远程桌面虚拟机(云桌面多租户)
    云手机

1.3 GPU虚拟化分类

根据GPU子系统实现分层,虚拟化技术也可以实现在三个层次,即用户层、内核层和硬件层:
    用户层:API 拦截和 API forwarding
    内核层:GPU 驱动拦截; GPU 驱动半虚拟化(Para Virtualization)
    硬件层:硬件辅助虚拟化; SRIOV(Single Root I/O Virtualization); Nvidia MIG(Multi-Instance GPU)

2. 用户层

在用户态图形API函数库(如libopenglES)进行拦截和转发,可以在本地转发,也可以转发到别的系统

2.1 本地 API 拦截和 API forwarding

1. 在用户态实现一个函数库,假设叫 libwrapper,它要实现底层库的所有API
2. 让APP调用这个libwrapper => 如何实现?底层动态库 + 用dlopen打开
3. libwrapper拦截用户的函数调用,对函数进行解析,然后使用参数去调用实际的底层库相同名称的函数
4. 调用完成后,libwrapper 把结果返回给 APP
案例:Chromium

2.2 远程 API forwarding

1. libwrapper 通过网络,去调用不同机器上的底层库
2. libwrapper 变成两部分,client 用于转发,和server用于接收和调用
3. 可以实现GPU池化(即多个GPU可以组成调用池,由多个client来调用),可以做到不具备GPU的机器能实现GPU的功能
案例:AWS Elastic GPU, rCUDA, Bitfushion 都是基于CUDA计算的,还没看到图形渲染API forward开源案例。
  • 案例1:AWS Elastic GPU。基于Nvdia GPU用于CUDA计算,参考 https://zhuanlan.zhihu.com/p/618496091
    在这里插入图片描述
    在这里插入图片描述

  • 案例2:rCUDA
    在这里插入图片描述

  • 案例3:Bitfusion
    在这里插入图片描述

2.3 半虚拟化 API forwarding

1. APP 和 libwrapper 运行在虚机中
2. libwrapper 通过半虚拟化方式(virtio)进行通讯,调用宿主机的底层库
3. 虚机的内核要实现 virtio-gpu frontend 
4. 宿主机的 hypervisor 实现 virtio-gpu backend
5. 宿主机完成底层库的调用
案例:swiftshader,drm_virgl,gfxstream

2.3.1 基于Virtio-GPU的Android虚拟化

谷歌Android Cuttlefish/Goldfish支持的Virtio-GPU虚拟化方案, 支持以下的gpu虚拟化方式
参考谷歌官方:https://source.android.com/docs/setup/create/cuttlefish-ref-gpu?hl=zh-cn
对比swiftshaderdrm_virglgfxstream
绘制硬件CPUGPUGPU
性能对比<10%~20%~70%
vmm支持qemu/crosvmqemu/crosvmcrosvm
图形APIopenGLES/VulkanopenGLESopenGLES/Vulkan

在这里插入图片描述

架构对比:
    1. 在Android Guest VM 端,Mesa或goldfish-opengl将OpenGLES命令分别编码为Gallium流或自动生成的GLES流。
    2. virtio-gpu内核驱动程序用作命令流传输。
    3. 在主机端,virglrenderer (用于 Mesa)和vulkan-cereal(用于goldfish-opengl )在现有 GPU驱动程序之上重播解码的命令流。 

2.3.2 swiftshader

  • Trout中基于virtio-gpu 2D的图形显示方案

2.3.3 drm_virgl

2.3.4 Gfxstream

  • Trout中支持基于virtio-gpu的gfxstream图形加速方案
  • QNX中支持基于virtio-gpu的gfxstream图形加速方案

QNX支持的基于virtio-gpu的gfxstream图形加速方案
参考:https://blackberry.qnx.com/en/products/foundation-software/qnx-hypervisor/advanced-virtualization-frameworks

3. 内核层

在内核层进行调用拦截,有虚拟设备文件进行拦截方案,也有内核驱动半虚拟化方案

3.1 设备文件拦截

    内核拦截模块模拟一个设备文件,内核拦截模块将用户进程的访问转发到(真实的)驱动软件,然后将对应内核函数的返回解析,再返回用户态。
        a. 通常底层库通过设备文件访问 GPU 驱动的功能,假设为 /dev/realgpu
        b. 实现一个内核模块,输出模拟的设备文件给用户空间,假设为 /dev/realgpu
        c. 把模拟的设备文件 bind mount 到容器里,伪装成真的设备文件 /dev/realgpu
        d. APP 和底层库都在容器里运行,底层库访问伪装的设备文件 /dev/realgpu,此时所有访问被内核模块拦截

3.2 QNX 8155

8155车机是一种设备文件拦截的GPU虚拟化方案

在这里插入图片描述
在这里插入图片描述

  • Android绘图指令通过/dev/下设备节点被转发到PVM(QNX仪表)中进行绘制,PVM中有完整的图形栈
  • Cluser挂了,IVI一定会挂
  • QNX中WFD框架管控所有屏幕和图层,可以在IVI图层中挖洞,提前亮屏等操作
  • 参考:https://blog.csdn.net/liaochaoyun/article/details/127391509

3.2 驱动半虚拟化

    用户进程通过系统虚拟化层(hypervisor)提供的虚拟化接口,访问(真实的)虚拟化接口。
        a. APP 和底层库都在虚机里
        b. 虚机的 GPU 驱动实现半虚拟化接口,通过类似 hypercall 的方式,调用宿主机实际的 GPU 驱动
        c. hypercall 切换 guest 到 hypervisor, hypervisor 通过内核中的驱动代理来访问实际的 GPU 驱动
        例如,车机中的 GPU 虚拟化。基于 type 1 的 hypervisor 虚拟化技术,支持多个 Guest。

在这里插入图片描述

4. 硬件层

硬件辅助的GPU虚拟化,从硬件层面虚拟出多个子GPU,每个子GPU可用于独立渲染。需要GPU芯片厂商提供实现。

4.1 SRIOV

4.2 Nvidia MIG

4.3 PowerVR

Series6系列GPU内核开始,PowerVR就具备了先进完备的硬件虚拟化特性
如芯驰X9使用的Imagination的PowerVR Series 9XM,支持硬件辅助虚拟化

4.4 Arm Mali G78AE

在这里插入图片描述

Mali G78AE GPU:带来了对虚拟化的硬件支持,可以直接访问多达16个虚拟机 (VM),从而以标准的时间片方法共享资源。目前没看见已量产的开发板,预估2024年以后。
;