ref CUDA 6 |中的统一内存英伟达开发者博客 (nvidia.com)
ref 提高 GPU 内存超额订阅性能 - NVIDIA 开发者博客
1. 什么是统一内存(UM)
在CUDA6.0之后引入了一个概念Unified Memory。这是一个软件层面的概念。通过复杂的同步逻辑赋予GPU 和 CPU 一片共同使用的虚拟内存。这片内存的同步动作由读写事件或上层API调用触发。这里并不消除同步内存的开销,只是通过适当地逻辑让开销被overlap。
这里需要注意,多数情况将同步内存动作的控制逻辑交给UM并不能使程序性能达到最佳。我们需要使用固定内存 + ( UM + 预取 ) 实现最佳的访存性能。
2. 区分 统一内存(UM) 和 统一虚拟寻址(UVA)
讲到Nvidia的UM就必须解释清楚UVA。UM的实现是基于UVA的。
UVA (Unified virtual addressing) 是CUDA4.0之后引入的内存管理系统,影响虚拟内存的分配。UVA通过统一CPU、GPU虚拟地址的方式使GPU能够确定虚拟内存的物理设备(反之不可行,CPU不能通过UVA确定虚拟内存的物理设备。具体原因在于UVA的实现)。CUDA获取虚拟地址物理属性的API是cuPointerGetAttribute。
支持UVA的内存系统在CUDA运行初始化时将虚拟地址(VA)划分为两个区域:
- CUDA VA Space: 所有CUDA管理的指针都在这个VA范围内。这片内存又可以分为三部分
- GPU 映射GPU内存的虚拟内存页面,禁止从主机访问。
- CPU 映射CPU内存的虚拟内存页面。允许从主机和GPU通过同样的VA访问。
- FREE 备用空间,由GPU控制和分配。
- CPU VA Space
这样的分区能让CUDA运行时根据虚拟地址的分配位置确定物理地址的设备类型。CUDA分配虚拟地址的API是cudaMalloc、cudaHostAlloc。
由此可见,UVA是当前CUDA虚拟地址的实现基础。UM是UVA之上的阁楼。二者并无并列关系。不要将其混淆。
3. 如何高效使用统一内存
上文我们提到直接使用UM不能获得最好的总体性能。下文通过一系列实验获得一些使用UM的指导意见。
实验通过超量使用内存的方式对比统一内存在GPU内存超额系数0.5-3.0情况下的性能差异。
3.1. 实验数据对比导读
- 实验数据中的访问方式包括gridstride(跳内存访问),blockstride(块状连续内存访问),randomwarp(随机访问)。
- 实验结果图表的纵轴为访问速度,横轴为超额订阅系数。超额订阅系数为1.0时订阅内存等同于GPU内存大小。
- 实验中的GPU有三种。V100GPU是volta架构nvidia-gpu,硬件总线接口是pcie3。其余两个GPU分别在V100GPU基础上提升了访问总线的性能和更先进的GPU架构。
- 实验结果图表共三个。
- 自适应的统一内存(默认的内存配置,会产生Page Fault,左图)
- 固定内存(提前预订内存所在的设备cudaMemAdvise或者使用非映射内存cudaMallocHost,会产生0拷贝现象,中图)
- 统一内存配合2MB页面的预取(使用cudaMemAdviseSetAccessedBy或cudaMemPrefetchAsync,右图)
3.2. 实验结果得出结论
- 固定设备页面的访问性能总是最好的,应尽量使用。
- 预取 + CPU内存页大小的步长,能在内存访问重叠的情况下获取更好的性能。
3.3. 一些编程建议
仍然可以全部使用UM内存类型。在需要使用固定页时采用cudaMemAdvise设定内存位置。在使用重叠访问时使用cudaMemAdvise或cudaMemPrefetchAsync以页大小步长动态调整内存位置。