【发布时间】:2017-02-25 12:37:36
【问题描述】:
我有一个简单的 CUDA 内核,我认为它可以有效地访问全局内存。然而,Nvidia 分析器报告说我正在执行低效的全局内存访问。我的内核代码是:
__global__ void update_particles_kernel
(
float4 *pos,
float4 *vel,
float4 *acc,
float dt,
int numParticles
)
{
int index = threadIdx.x + blockIdx.x * blockDim.x;
int offset = 0;
while(index + offset < numParticles)
{
vel[index + offset].x += dt*acc[index + offset].x; // line 247
vel[index + offset].y += dt*acc[index + offset].y;
vel[index + offset].z += dt*acc[index + offset].z;
pos[index + offset].x += dt*vel[index + offset].x; // line 251
pos[index + offset].y += dt*vel[index + offset].y;
pos[index + offset].z += dt*vel[index + offset].z;
offset += blockDim.x * gridDim.x;
}
特别是分析器报告以下内容:
来自 CUDA best practices guide 它说:
“对于计算能力为 2.x 的设备,可以很容易地总结要求:warp 线程的并发访问将合并为与服务所需的缓存行数相等的事务数warp 的所有线程。默认情况下,所有访问都通过 L1 缓存,作为 128 字节的行。对于分散的访问模式,为了减少过度读取,有时只缓存在 L2 中是有用的,它缓存较短的 32-字节段(参见 CUDA C 编程指南)。
对于计算能力 3.x 的设备,对全局内存的访问仅缓存在 L2 中; L1 保留用于本地内存访问。一些计算能力为 3.5、3.7 或 5.2 的设备也允许在 L1 中选择加入缓存全局变量。"
现在在我的内核中,基于此信息,我预计需要 16 次访问才能为 32 线程扭曲提供服务,因为 float4 是 16 字节,并且在我的卡(770m 计算能力 3.0)上,从 L2 缓存读取是在 32 中执行的字节块(16 字节 * 32 线程 / 32 字节缓存线 = 16 次访问)。确实,正如您所看到的分析器报告我正在进行 16 次访问。我不明白为什么分析器报告理想的访问将涉及第 247 行的每次访问 8 个 L2 事务,而其余行的每次访问仅涉及 4 个 L2 事务。有人可以解释我在这里缺少什么吗?
【问题讨论】:
标签: caching memory cuda profiler