AMD GPU VMID
本文所讨论的均为AMD公司的显卡产品
显卡:AMD Radeon RX 5500 - 8GB 显存
Linux:Linux-5.4.y (fc944ddc0b4a)
AMD GPU HUB
在AMD GPU内部有很多种类的IP,这些不同种类的IP硬件一起构成了完整的GPU硬件,这些子IP在运行的时候也需要访问VRAM或者sysMem的资源,但是不同的是,这些IP并没有与实际的Memroy Controler(MC) 相连,而是汇总到一个称作为“HUB”的硬件单元上,由这个硬件单元代理进行统一的寻址,这个硬件和我们在计算机上看到南桥(PCH: Platfrom Controller Hub)很类似,计算机将一些低速的设备(NIC, SATA, USB ..) 连接到南桥,再由南桥芯片统一和CPU进行通信。
由于GPU硬件设计的需要,在AMD GPU内部集成了一个或者多个HUB硬件,系统将不同种类的IP硬件连接到不同的HUB上,由HUB代理IP进行IO访问,GPU内部IP大多数设备都是基于HUB来进行内存访问的。
HUB | IP | Note |
---|---|---|
GFX HUB (1个) | GC (Graphic Core), sDMA | 主要计算单元: SE/SH/CU/SIMD |
MM HUB (1个或者多个) | UVD, VCE, VCN, JPEG, DCN | 多媒体: 编码解码等IP |
GPU HUB 功能
GPU HUB主要由以下几种功能:
- 地址翻译:将GPU的虚拟地址翻译成总线地址
- TLB:Translation Lookaside Buffer 提供了一个Cache硬件用于加速地址翻译
AMD GPU硬件提供了2种地址翻译机制:
- GPU VM:由GPU自身完成地址翻译,并将翻译的结果直接送到地址总线进行寻址。(主要模式)
- ATC/ATS:由IOMMU提供地址翻译过程,并将翻译结果缓存到ATC中。(APU)
- ATS: Address Translation Services 基于PCIE协议的ATS服务, 需要搭配IOMMU使用
- ATC: Address Translation Cache 用于缓存地址翻译结果(aka IO-TLB)
VMID (Virtual Memory/Machine Identity)
由于HUB自身提供了地址翻译功能,那么上游的IP就可以用虚拟的GPU地址用于内存访问,简化了编程门槛,同时提隔离了不同VM的虚拟地址空间。
AMD GPU提供了为每个HUB提供了16份VMID,意味着每个HUB在统一时刻可以表示16份不同的地址空间,软件在提交Command的时候需要将自己VM的GPU虚拟地址空间绑定到一个VMID上,由这个VMID来表示GPU虚拟地址空间的layout,通俗来讲GPU有16个MMU单元可以同时地址翻译功能。
尽管每个HUB由16个VMID,但是在硬件设计的时候VMID-0是比较特殊的:
- GART 地址空间在VMID-0上 KMD提交Command是在VMID-0上
- VMID-0提供System Aperature概念,简化内核态的物理地址翻译过程
VMID 分配
在Linux平台上VMID按照如下用途进行分配
VMID | Use | |
---|---|---|
0 | GART | Kernel Submit Command |
1 - 7 | User 3D Application (/dev/card0, render128) | opengl, vulkan, 等3D程序 |
8 - 15 | KFD Application (/dev/kfd) | Hip,Rocm等程序 |
VMID 虚拟地址空间
GPU虚拟地址范围
本文所讨论的AMD Radeon RX 5500显卡是一个64位的GPU,但是实际的虚拟地址范围是48bit,也就是寻址能力是2^48。
AMD 的GPU虚拟地址范围会影响GPU页表的翻译级数,随着地址宽度的 增加,翻译级数也需要随着增加,否则会浪费更多的页表内存,页表级数的增加意味着翻译效率的降低,在AMD GPU kernel Driver中,GPU VM的虚拟地址范围由 System Memory 和 VRAM的大小计算出来的。
计算方法如下:
1 | void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size, |
另外你可以在kernel的log里看到如下信息
1 | [ 65.752676] [drm] vm size is 262144 GB, 4 levels, block size is 9-bit, fragment size is 9-bit |
其中 262144 GB (= 0x1000000000000) 就是KMD 计算出来的VM SIZE,这个大小会通过ioctl命令report给libdrm,供libdrm va-range分配器使用。
GPU 页表级数
AMD GPU硬件支持 4 + 1级页表映射,一共最多可实现5级映射, +1级映射会影响TLB效率一般不使用。
AMD GPU Page Size 固定为4K 大小。
GPU页表翻译的时候使用的是物理地址翻译,但是GPU_PAGE_SIZE 为4k,当前的驱动并不能保证一定分配出多个连续的page作为PTE或者PDE。
那么一个4K的物理配置能装多少个PTE呢?
1 PTE = 8 Bytes
1 PAGE = 4 K
Count = 4K / 8 = 512 PTEs = 2 ^ 9 PTEs
通过上面的公式可以算出来,一个4k的物理page可以装下512个页表项,同理一个4k的物理page也可以装下512个目录项,所以对于4级页表一般按照如下分配:
- 64 VA: 9 - 9 - 9 - 9 - 12
- 32 VA : 10 - 10 - 10 -12
VMID的使用
GPU在提交Command到GPU上,必须获得一个可以使用的VMID,并把自己的页表基地址设置到对应的VMID寄存器上,当前VMID才能表示当前GPU进程的GPU虚拟地址空间。后面的shader,纹理,fence等GPU资源才能正常工作。
VMID作为GPU硬件资源他的数量是有限的,当多个GPU进程同时运行时,需要分时的复用这些VMID资源,才能保证不同GPU进程工作正常。
由于VMID自身硬件自身的Cache(TLB)存有地址翻译的结果,所以当GPU进程切换的时候务必需要进行Cache Flush操作,这样不可避免的会造成性能的浪费,后面的文章我会详细描述一下 VMID 的分配算法。
总结
希望这篇文章对你理解GPU VM有所帮助,错误的地方请联系作者改正。