我正在尝试在 CUDA 的帮助下减少 65536 个元素数组(计算其中元素的总和)。内核如下所示(请暂时忽略 *dev_distanceFloats 和索引参数)
__global__ void kernel_calcSum(float *d, float *dev_distanceFloats, int index) {
int tid = threadIdx.x;
float mySum = 0;
for (int e = 0; e < 256; e++) {
mySum += d[tid + e];
}
}
ant 它作为一个具有 256 个线程的块启动:
kernel_calcSum <<<1, 256 >>>(dev_spFloats1, dev_distanceFloats, index);
到目前为止,一切顺利,256 个线程中的每一个都从全局内存中获取 256 个元素,并在局部变量 mySum 中计算它的总和。内核执行时间约为 45 毫秒。下一步是在块中的这 256 个线程之间引入共享内存(以计算 mySum 的总和),因此内核变为如下:
__global__ void kernel_calcSum(float *d, float *dev_distanceFloats, int index) {
__shared__ float sdata[256];
int tid = threadIdx.x;
float mySum = 0;
for (int e = 0; e < 256; e++) {
mySum += d[tid + e];
}
sdata[tid] = mySum;
}
我刚刚添加了对共享内存的写入,但执行时间从 45 毫秒增加到 258 毫秒(我在 NVidia Visual Profiler 5.0.0 的帮助下对此进行了检查)。我意识到在写入 sdata 变量时每个线程有 8 个存储库冲突(我在 GTX670 上,它具有 32 个存储库的能力 3.0)。作为一个实验——我尝试在启动内核时将线程数减少到 32 个——但时间仍然是 258 毫秒。
问题 1:为什么在我的情况下写入共享内存需要这么长时间?问题 2:是否有任何工具可以详细显示“执行计划”(内存访问时间、冲突等)?
感谢您的建议。
更新: 使用内核 - 我将 sdata 设置为每个线程的某个常量:
__global__ void kernel_calcSum(float *d, float *dev_distanceFloats, int index) {
__shared__ float sdata[256];
int tid = threadIdx.x;
float mySum = 0;
for (int e = 0; e < 256; e++) {
mySum += d[tid + e];
}
sdata[tid] = 111;
}
时间回到 48 毫秒。所以,改变 sdata[tid] = mySum; 到 sdata[tid] = 111; 做了这个。
这个编译器优化(可能只是删除了这一行?)还是出于某种原因从本地内存(寄存器?)复制到共享需要很长时间?