1. 为什么需要 GPU 虚拟地址(GPUVA)?
现代GPU早已不再是简单的图形渲染加速器,而是演变成了通用计算设备。这种演变带来了一个关键问题:如何高效管理GPU可访问的内存空间?GPU虚拟地址(GPUVA)机制应运而生。
在早期GPU架构中,CPU和GPU之间的内存交互采用"乒乓缓冲区"模式。CPU将数据拷贝到固定物理地址的显存中,GPU直接访问这些物理地址。这种方式简单粗暴,但存在严重缺陷:
- 地址空间碎片化:频繁分配释放导致显存利用率低下
- 安全性问题:所有进程都能访问整个显存空间
- 扩展性差:无法支持多任务并行处理
GPUVA的引入解决了这些痛点。它通过MMU(内存管理单元)为每个进程创建独立的虚拟地址空间,实现了:
- 地址空间隔离:不同进程的GPUVA相互独立
- 按需分配:物理内存只在访问时映射
- 统一寻址:CPU和GPU可以共享同一虚拟地址空间
提示:现代GPU架构如NVIDIA的Ampere、AMD的CDNA2都采用了统一的虚拟地址空间设计,CPU和GPU可以共享同一套指针,极大简化了异构编程模型。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. GPUVA分配的全局流程
完整的GPUVA分配涉及驱动层、硬件层和运行时库的协同工作。典型流程如下:
-
应用层请求:
- 应用程序通过API(如CUDA的cudaMalloc)申请GPU内存
- 运行时库将请求转发给KMD(Kernel Mode Driver)
-
驱动层处理:
- KMD创建GPUVA范围(通常通过ioctl)
- 分配物理内存(显存或系统内存)
- 建立页表映射
-
硬件层生效:
- GPU MMU加载新的页表项
- TLB(转换后备缓冲区)更新
c复制// 简化的Linux DRM驱动示例
int drm_gpuva_alloc(struct drm_device *dev, size_t size) {
struct drm_gem_object *obj;
int ret;
// 创建GEM对象
obj = drm_gem_create(dev, size);
if (IS_ERR(obj))
return PTR_ERR
