假设这样的简单内核:
__global__ void fg(struct s_tp tp, struct s_param p)
{
const uint bid = blockIdx.y * gridDim.x + blockIdx.x;
const uint tid = threadIdx.x;
const uint idx = bid * blockDim.x + tid;
if(idx >= p.ntp) return;
double3 r = tp.rh[idx];
double d = sqrt(r.x*r.x + r.y*r.y + r.z*r.z);
tp.d[idx] = d;
}
这是真的吗?:
double3 r = tp.rh[idx];
数据从全局内存加载到r变量中。
r存储在寄存器中,或者如果有很多变量,则存储在本地存储器中。
r未存储在共享内存中。
d,然后将其写回全局存储器。
寄存器比其他存储器更快。
如果寄存器空间已满(某些大内核),则使用本地内存,访问速度较慢
当我需要双打时,有什么方法可以加快速度吗?例如,首先将数据加载到共享内存中然后再运行它们?
感谢所有人。
答案 0 :(得分:2)
是的,这几乎都是真的。
•当我需要双打时,有什么方法可以加快速度吗?例如,首先将数据加载到共享内存中然后再操作它们?
当数据重用(多次加载相同的数据项,通常由线程块中的多个线程加载)时,或者当您专门使用共享内存来帮助时,使用共享内存非常有用全局合并,例如在optimized matrix transpose期间。
数据重用意味着您多次使用(加载)数据,并且对于共享内存有用,这意味着您要通过多个线程多次加载它。如果您在一个线程中多次使用它,那么单个加载以及将其存储在寄存器中的编译器(自动)“优化”就是您所需要的。
修改强> @Jez给出的答案对于最佳加载有一些好的想法。我建议另一个想法是将您的AoS数据存储方案转换为SoA方案。数据存储转换是提高CUDA代码速度的常用方法。
您的s_tp
结构(未显示)似乎每个项目/结构有多个double
数量的存储空间。如果您为这些数量中的每一个创建单独的数组,您将有机会获得最佳的加载/存储。像这样:
__global__ void fg(struct s_tp tp, double* s_tp_rx, double* s_tp_ry, double* s_tp_rz, double* s_tp_d, struct s_param p)
{
const uint bid = blockIdx.y * gridDim.x + blockIdx.x;
const uint tid = threadIdx.x;
const uint idx = bid * blockDim.x + tid;
if(idx >= p.ntp) return;
double rx = s_tp_rx[idx];
double ry = s_tp_ry[idx];
double rz = s_tp_rz[idx];
double d = sqrt(rx*rx + ry*ry + rz*rz);
s_tp_d[idx] = d;
}
对于类似类型的使用模式,此方法也可能在您的设备代码的其他地方带来好处。
答案 1 :(得分:1)
一切都是真的。
当我需要双打时,有什么方法可以加快速度吗?例如加载 数据首先进入共享内存然后运行它们?
对于您提供的示例,您的实现可能不是最佳的。您应该做的第一件事是将实现的带宽与参考内核的带宽进行比较,例如cudaMemcpy。如果差距很大,并且通过缩小这一差距而获得的加速很有意义,那么可能会进行优化。
看看你的内核有两件事让我感到不太理想:
编辑:Robert Crovella在下面的回答为第二点提供了一个很好的解决方案,需要改变您的数据类型。出于某种原因,我原本以为这不是一个选项,所以如果你只是改变你的数据类型,下面的解决方案可能是过分的!
虽然为每个线程添加更多工作是一件相当简单的事情,但是为解决方案优化内存访问模式(不更改数据类型)则不那么容易。幸运的是,有些库可以提供帮助。我认为使用CUB,特别是BlockLoad集合,应该允许您更有效地加载。通过使用转置运算符为每个线程加载6 double
个项目,您可以为每个线程处理两个元素,将它们打包到double2
中,并正常存储它们。