1. CUDA内存模型深度解析
在GPU加速计算中,理解内存模型是性能优化的关键所在。CUDA的内存体系远比CPU复杂,它包含了多种具有不同特性的存储空间,每种空间都有其独特的访问特性和使用场景。
1.1 内存层次结构详解
CUDA设备包含以下主要内存类型:
-
全局内存(Global Memory)
- 容量最大(通常为GB级别)
- 延迟最高(400-600个时钟周期)
- 所有线程都可访问
- 生命周期与应用程序相同
- 使用
cudaMalloc分配,cudaFree释放
-
共享内存(Shared Memory)
- 片上内存,速度接近寄存器
- 延迟极低(约1个时钟周期)
- 仅块内线程共享
- 使用
__shared__关键字声明 - 典型大小:每个SM 64KB(可配置)
-
寄存器(Registers)
- 速度最快,零延迟
- 每个线程私有
- 数量有限(每个线程最多255个32位寄存器)
- 自动分配给局部变量
-
常量内存(Constant Memory)
- 只读内存
- 有专用缓存(constant cache)
- 适合存储不会改变的数据
- 使用
__constant__关键字声明
-
纹理内存(Texture Memory)
- 专为空间局部性访问优化
- 有专用缓存
- 支持硬件插值等特殊操作
提示:实际编程中,90%的性能优化机会来自全局内存和共享内存的合理使用。
1.2 内存访问模式与性能
CUDA内存性能的关键在于合并访问(Coalesced Access)。当线程束(warp,32个线程)访问全局内存时,如果满足以下条件,硬件可以将这些访问合并为一次或少数几次内存事务:
- 线程访问连续的内存地址
- 起始地址对齐到32字节边界
- 访问的数据大小是32/64/128位
不满足合并条件的访问会导致"内存事务分裂",显著降低性能。例如,以下代码展示了理想的合并访问模式:
c复制__global__ void good_access(float *output, float *input) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
output[tid] = input[tid] * 2.0f; // 合并访问
}
而以下则是典型的非合并访问模式:
c复制__global__ void bad_access(float *output, float *input) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
output[tid] = input[tid
