浅论Intel GPU虚拟化实现方案GVT

引用注明>> 【作者:张佩】【原文:http://www.yiiyee.cn/Blog/

v0.3 (未完成版,慎勿转载)

kvmgt
KVMGT未upstream前的架构图

在最近的Linux内核4.10的发布中,Intel的GPU虚拟化方案(GVT)完成了代码上传,从此成为Linux内核的一部分。GVT在4.10的发布文档中,作为主要的新特性之一而被发布者隆重地介绍。在过去的两年中,我作为一名开发者,参与到了GVT的开发过程中。对此重大里程碑事件深感欣慰。将陆续写作一些文章,对Inte的GPU驱动和虚拟化实现,进行由粗入细的介绍。

我近来对于一些计算机术语,产生了一点个人趣味上的偏好,细节在此不能备述,容后专文细讲。这里就两个用惯的术语,要在文章中,做很大的习惯上的改变,读者可能会觉得很不适应。无法,我确定了要这样做,只能请读者忍耐。

术语新译
Context:境(一般译作:上下文)
Execution Context:执行境
Hardware Context: 硬境
Logic Context:拟境
buffer:囊(一般译作:缓冲区)
Ring buffer:环形囊

  • 一般原理
 当虚机提交了一个执行境,由于显卡没有硬件虚拟化,所以它不能直接处理这个执行境,因为硬件不能理解这个执行境里涉及的全部地址,这些地址,都是主机虚拟给虚机使用的,不是真实物理地址。GVT在中间横了一道,把虚机提交的执行境拿过来,按下不表,自己却提交了一个新的执行境给硬件执行,称作影子执行境。影子执行境的创建,当然是根据虚机执行境的内容进行的(此处对虚机产生性能影响)。GVT等待影子执行境处理完了,再给虚机扮演GPU,来根据本处理好的执行境的变量,来处理虚机执行境,最后模拟执行境的完成。唯有如此,GVT才能准确而无遗漏地模拟物理GPU。
模拟其实是分成了两步来实现的,第一步是产生一个影子执行境,提交给硬件,此处需要创建一个物理设备真实可用的执行境,是模拟的第一个难点;第二步是影子执行境完成后,模拟虚机执行境的完成,这是模拟的第二个难点。把这两点都实现好了,虚机就能畅通无阻,完全像躺在硬件的河床上,流淌它的3D语义了。此处容后展开来言谈,此处三言两语带不过。
  • 拟境(Logic Ring Context)的组成
 拟境是一个执行境在驱动里面的表现形式,在没有提交给硬件执行前,它只是逻辑上的(Logic)执行境(Context),我将它称作“拟态”的。拟境的结构体组成,和执行境是完全一样的。
各位知道,执行境是一个自我完备的执行环境。在旧的硬件平台上,硬件有唯一的执行环境,就是位于每个执行引擎上的ring bufer(环形囊)。驱动程序每次提交GPU命令(Execution Buffer)的时候,就是往这个唯一的环形囊中填写GPU能理解的一条条指令和数据。不管系统中有多少个应用程序在并发地利用执行引擎,命令提交给驱动,落实到最后提交的时候,都在同一个环形囊上操作。为了让这种操作紧张有序地进行,执行引擎专门有两个环形囊的位置寄存器来控制,一个指向环形囊的头,表示执行引擎执行到的位置(类似CPU的IP寄存器);另一个指向环形囊的尾,表示最后一次填充的指令的地方,下次再有指令填充进来,就从这个尾部开始递增(如果到了环形囊的最后,要回绕到环形囊的起始地址)。
这种方案当然比较地简单,也很有效。主要的问题是,这种方式不能在硬件上区分DMA囊。多个DMA囊提交给硬件后,硬件就胡子连辫子,一把抓,分不清谁跟谁了。因为在环形囊里面的,不外乎是GPU指令,硬件没法区分它们来自哪里。另外一个问题,是GPU指令的抢占,在这种模式下实现起来不便利。一般的强占,是以DMA囊为单位进行的。用户提交了一个很大的DMA囊给硬件执行,过了1秒钟还没有完成,系统认为它执行的时间太长了,可能会影响用户图形交互的响应速度,决定把上面的那个命令取消的。在环形囊的模式下,内核驱动就只能提交一个专门的强占DMA囊到执行引擎的另一个环形囊上。当前正在环形囊上执行的所有指令,就会在一个点上终止执行。
那么,换到Execlist模式下之后,事情就变得简单。执行引擎不再自己维持环形囊了,而等在Excelist中,让驱动自己将环形囊提交上来,自己再执行。每个提交上来的环形囊,其实是被一个执行境所包裹了,执行境中除了有环形囊,还有别的一些信息,比如这个执行境ID(lrc ID),环形囊的起始地址和首尾位置,PPGTT页表地址(GPU指令中会用到这个虚拟地址)等。这样一来,不同的DMA囊就很容易被区分,当出现GPU Hang的时候,就可以知道是哪个DMA囊出现的问题,更容易跟踪问题。抢占也容易实现了,如果要强占一个已经提交的执行境(环形囊/DMA囊),只要再提交一个新执行境就可以了,不必专门组织一个用于抢占的DMA囊。
现在来讲讲一个执行境的组成。作为一个执行境,必然要包含用于具体执行的详细参数。GPU执行境的执行境比较大,HSW是19个物理页,BDW是22个物理页。这里面的内容,在I915驱动中,有具体的展示,以BDW为例,它包括了这些内容。
  • I915提交执行境的过程
 用户层驱动负责把用户程序的图形命令翻译成GPU指令,并通过命令囊(Execution Buffer) 发送下来。I915对上的接口是I915_gem_execbuffer2函数,对应的IOCTL是I915_GEM_EXECBUFFER2。它的输入参数中包含了命令囊的结构体。接到一个新命令囊后,I915进行处理,先要将命令囊封装到执行境中。每个用户程序都会在图形初始化的时候,先创建一个或多个执行境,提交命令的时候,会指定将命令囊关联到哪个执行境上。命令囊中有一个参数,是指定执行境ID的。I915根据此ID找到内部的执行境结构体。命令囊还包含了数据囊(就是自己的环形囊)的信息,这些数据囊也是预先向I915申请的,各自有一个句柄标识之,命令囊中包含了数据囊的句柄。
收到新命令囊后,I915会检查其执行境,和当前硬件使用的执行境是否相同,如果不相同的话,需要设置切换点。对于传统的环形囊模式,切换的实施,是通过在数据囊中添加MI_SET_CONTEX指令,并指定新提交的拟境地址(见函数mi_set_context)。
    intel_ring_emit(ring, MI_SET_CONTEXT);
    intel_ring_emit(ring, i915_ggtt_offset(req->ctx->engine[RCS].state) | flags);
对于Execlist模式,执行境的切换由硬件自动完成,不必插入显式的指令。硬件检查新提交的拟境和当前执行境的异同,同时还会参考拟境描述符中的Flag设置,决定是否需要进行执行境切换。驱动向ExecList端口写入拟境描述符来完成提交,这个描述符是两个DWORD组成的,共8字节。它各部分的含义,在I915驱动中有如下的介绍(见函数intel_lr_context_descriptor_update):
 /* This is what a descriptor looks like, from LSB to MSB::
 *
 *      bits  0-11:    flags, GEN8_CTX_* (cached in ctx_desc_template)
 *      bits 12-31:    LRCA, GTT address of (the HWSP of) this context
 *      bits 32-52:    ctx ID, a globally unique tag
 *      bits 53-54:    mbz, reserved for use by hardware
 *      bits 55-63:    group ID, currently unused and set to 0
 */
两个重要的值,一个是境ID,此值唯一,驱动和硬件用以标识和追踪执行境。一个是LRCA,是当前提交的拟境所在的地址。如果当前拟境和前面的拟境完全不同,或者调用者通过flags值要求强制进行执行境切换(gvt下,就是每次都需要强制切换,因为所有的虚机公用一个拟境结构体),硬件便会在执行环形囊中的指令前,先进行境切换。执行境切换比较耗时,在GVT实现中,如果能优化调度器的算法,尽量减少硬件的境切换的次数,是可以提高GPU的整体性能的。
  • 影子拟境
基本原理是在不打破虚机拟境的前提下——打破了还需要恢复,很麻烦,所以不如不打破,留着它——新建一个影子拟境(简称影境),提交给硬件执行。这个过程称为影境构造。在GVT的实现里面,每个硬件引擎,有一个影境。影境构造的具体过程,是先把虚机拟境的22个页全部拷贝到硬境中,然后修改具体的某些值(head/tail/ctr/page table),同时,要构造新的环形囊。麻烦的是重建环形囊的过程,需要将虚机环形囊的每个GPU指令都过一遍,在代码中,这称作命令扫描(command scan,见gvt函数command_scan)。对于使用到的每个地址,替换成真实的硬件地址后,填如硬境的命令囊中。
当影境提交后,硬件执行它。执行成功后,系统收到一个执行境完成的中断。这时候,影境被硬件执行过一遍,参数发生了变化,需要把这些变化了的信息反馈给虚机。所以gvt要把影境的19/22个页重新拷贝回虚机拟境中,并虚拟一个拟境完成的中断。这样虚机中的驱动程序,就会认作自己提交的拟境,已经被硬件成功执行了,并进行后续的处理。整个虚拟过程,就这样完成了。棒棒哒!

8,627 total views, 2 views today

《浅论Intel GPU虚拟化实现方案GVT》有3个想法

发表评论

电子邮件地址不会被公开。