searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Virtqueue前后端交互分析

2022-12-30 02:22:54
220
0

关键词

Virtio:virtio是一个通用的io虚拟化框架,hypervisor通过他模拟出一系列的虚拟化设备,并使得这些设备在虚拟机内部通过api调用的方式变得可用。

Virtqueue:virtqueue是virtio前端和后端的抽象传输层

 

       virtio是虚拟化场景下的标准驱动模型。DPU在实现IO硬件卸载时,为了和虚拟化场景保持一致,基本都会选择virtio作为软硬件交互的接口。本文将重点分析virtio的核心数据结构--virtqueue,便于理解在硬件化virtio时,可能会遇到的困难。

  1. virtqueue的基本组成

       本文介绍virtio1.0的virtqueue的结构,virtqueue是vm在vm内存中创建的队列,该队列用于前(vm)后(hypervisor)端交互数据。    virtio1.0规范的virtqueue,由三个队列组成,分别是avail队列,desc队列,used队列。

       avail队列由vm写入,hypervisor读取,used队列由hypervisor写入,vm读取。desc作为一种资源,由vm负责管理,vm读写,hypervisor只读

  

        2.virtqueue的数据交互

             1)前端添加请求:vm向avail写入request,request可以是待发送数据或请求接收数据。每一个avail表项代表一个request,request的具体信息存放在desc队列中。vm每次向avail写入reqeust,都会更新avail->idx,表明vm的request更新到了avail的哪个位置。

          2)后端处理请求:hypervisor从avail读取request,从对应的desc中获取请求的具体信息(一般是buffer指针和长度)。hypervisor处理完request之后,将request的id写入used队列,表明出来已经完成。

                3)前端回收请求:vm读取used队列,从对应的desc获取到request的结果。

                4)内存布局:virtqueue的数据交互通过avail、used和desc队列实现前后端信息交互,所有的数据都在vm内存中,前后端采用共享内存的方式完成数据拷贝,避免了vm-exit。

                 5)硬件实现:在DPU中,virtio的后端从软件的hypervisor中剥离出来,由FPGA或者ASIC实现。virtqueue的数据结构没有变化,vm的操作流程也没有变化,但后端的数据操作从软件的内存拷贝变为了硬件的dma,提高了性能。

                 6)性能分析:

virtio最早是为软件设计的,一些交互流程对硬件并不友好,主要体现在:一次请求涉及到三个队列。需要从avail队列读id,再从desc队列读取request的具体内容,最后将处理结果写入used队列。硬件的高性能体现在可以一次性dma一大段地址。但是virtio的一次request需要分别操作三个队列,且相互之间存在依赖关系,需要串行访问。因此virtio1.1针对该问题将,virtqueue从三个队列合并为了一个队列。

 

          3.virtqueue的通知机制

                1)前端notify:virtqueue需要前后端配合完成数据交互,vm写入request,需要通知后端取request;后端完成处理,需要通知前端有完成的request。vm在写入request后,通过notify寄存器通知后端。在虚拟化环境下,notify寄存会引起vm-exit,并不是一个高效的方式。因此,vm的驱动软件会尽量做到批量添加request,然后发起一次notify。在virtqueue交互流程上,设计了notify抑制机制,即通过在共享内存中设计了一个flag标志,来表明是否需要vm写notify寄存器。该flag由后端负责设置,表明后端不需要notify。

                2)后端中断:后端完成处理时,通过中断通知vm处理完成。虚拟化环境下,中断注入也会造成vm-exit(post interrupt会相对友好些)。通过共享内存中的flag标志,当vm不需要中断通知时,vm设置该标志,后端不再发送中断。当vm驱动进去NAPI处理,或者用户态轮询时,可以设置该标志,禁止后端发送中断。

                3)性能分析:

      1. vm写notify寄存器通知后端有新的request,但是notify寄存器只包含request所在的队列,后端收到通知后,需要读取avail idx才知道avail队列具体有多少request需要处理。1改进了notify寄存器的格式,增加了队列的当前idx。当后端是硬件实现时,能够减少一次dma读idx的操作
      2. virtio使用共享内存存放flag,用于notify和中断抑制。这对软件没什么问题,但后端是硬件实现时,会增加硬件dma读小字节数内存的次数,硬件整体性能。
0条评论
0 / 1000
曾****健
3文章数
2粉丝数
曾****健
3 文章 | 2 粉丝
曾****健
3文章数
2粉丝数
曾****健
3 文章 | 2 粉丝
原创

Virtqueue前后端交互分析

2022-12-30 02:22:54
220
0

关键词

Virtio:virtio是一个通用的io虚拟化框架,hypervisor通过他模拟出一系列的虚拟化设备,并使得这些设备在虚拟机内部通过api调用的方式变得可用。

Virtqueue:virtqueue是virtio前端和后端的抽象传输层

 

       virtio是虚拟化场景下的标准驱动模型。DPU在实现IO硬件卸载时,为了和虚拟化场景保持一致,基本都会选择virtio作为软硬件交互的接口。本文将重点分析virtio的核心数据结构--virtqueue,便于理解在硬件化virtio时,可能会遇到的困难。

  1. virtqueue的基本组成

       本文介绍virtio1.0的virtqueue的结构,virtqueue是vm在vm内存中创建的队列,该队列用于前(vm)后(hypervisor)端交互数据。    virtio1.0规范的virtqueue,由三个队列组成,分别是avail队列,desc队列,used队列。

       avail队列由vm写入,hypervisor读取,used队列由hypervisor写入,vm读取。desc作为一种资源,由vm负责管理,vm读写,hypervisor只读

  

        2.virtqueue的数据交互

             1)前端添加请求:vm向avail写入request,request可以是待发送数据或请求接收数据。每一个avail表项代表一个request,request的具体信息存放在desc队列中。vm每次向avail写入reqeust,都会更新avail->idx,表明vm的request更新到了avail的哪个位置。

          2)后端处理请求:hypervisor从avail读取request,从对应的desc中获取请求的具体信息(一般是buffer指针和长度)。hypervisor处理完request之后,将request的id写入used队列,表明出来已经完成。

                3)前端回收请求:vm读取used队列,从对应的desc获取到request的结果。

                4)内存布局:virtqueue的数据交互通过avail、used和desc队列实现前后端信息交互,所有的数据都在vm内存中,前后端采用共享内存的方式完成数据拷贝,避免了vm-exit。

                 5)硬件实现:在DPU中,virtio的后端从软件的hypervisor中剥离出来,由FPGA或者ASIC实现。virtqueue的数据结构没有变化,vm的操作流程也没有变化,但后端的数据操作从软件的内存拷贝变为了硬件的dma,提高了性能。

                 6)性能分析:

virtio最早是为软件设计的,一些交互流程对硬件并不友好,主要体现在:一次请求涉及到三个队列。需要从avail队列读id,再从desc队列读取request的具体内容,最后将处理结果写入used队列。硬件的高性能体现在可以一次性dma一大段地址。但是virtio的一次request需要分别操作三个队列,且相互之间存在依赖关系,需要串行访问。因此virtio1.1针对该问题将,virtqueue从三个队列合并为了一个队列。

 

          3.virtqueue的通知机制

                1)前端notify:virtqueue需要前后端配合完成数据交互,vm写入request,需要通知后端取request;后端完成处理,需要通知前端有完成的request。vm在写入request后,通过notify寄存器通知后端。在虚拟化环境下,notify寄存会引起vm-exit,并不是一个高效的方式。因此,vm的驱动软件会尽量做到批量添加request,然后发起一次notify。在virtqueue交互流程上,设计了notify抑制机制,即通过在共享内存中设计了一个flag标志,来表明是否需要vm写notify寄存器。该flag由后端负责设置,表明后端不需要notify。

                2)后端中断:后端完成处理时,通过中断通知vm处理完成。虚拟化环境下,中断注入也会造成vm-exit(post interrupt会相对友好些)。通过共享内存中的flag标志,当vm不需要中断通知时,vm设置该标志,后端不再发送中断。当vm驱动进去NAPI处理,或者用户态轮询时,可以设置该标志,禁止后端发送中断。

                3)性能分析:

      1. vm写notify寄存器通知后端有新的request,但是notify寄存器只包含request所在的队列,后端收到通知后,需要读取avail idx才知道avail队列具体有多少request需要处理。1改进了notify寄存器的格式,增加了队列的当前idx。当后端是硬件实现时,能够减少一次dma读idx的操作
      2. virtio使用共享内存存放flag,用于notify和中断抑制。这对软件没什么问题,但后端是硬件实现时,会增加硬件dma读小字节数内存的次数,硬件整体性能。
文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0