我刚刚开始使用CUDA,并试图将我的大脑包裹在CUDA减少算法中。就我而言,我一直试图得到两个矩阵的点积。但我只得到大小为2的矩阵的正确答案。对于任何其他大小的矩阵,我错了。
这只是测试,因此我保持矩阵尺寸非常小。只有大约100个,所以只有1个块才适合它。 任何帮助将不胜感激。谢谢!
这是常规代码
float* ha = new float[n]; // matrix a
float* hb = new float[n]; // matrix b
float* hc = new float[1]; // sum of a.b
float dx = hc[0];
float hx = 0;
// dot product
for (int i = 0; i < n; i++)
hx += ha[i] * hb[i];
这是我的cuda内核
__global__ void sum_reduce(float* da, float* db, float* dc, int n)
{
int tid = threadIdx.x;
dc[tid] = 0;
for (int stride = 1; stride < n; stride *= 2) {
if (tid % (2 * stride) == 0)
dc[tid] += (da[tid] * db[tid]) + (da[tid+stride] * db[tid+stride]);
__syncthreads();
}
}
我的完整代码:http://pastebin.com/zS85URX5
答案 0 :(得分:2)
希望你能弄明白为什么它适用于n = 2的情况,所以让我们跳过它,看看它为什么在其他情况下失败,让我们选择n = 4。当n = 4时,您有4个线程,编号为0到3.
在for循环的第一次迭代中,stride = 1,因此传递if测试的线程是线程0和2。
thread 0: dc[0] += da[0]*db[0] + da[1]*db[1];
thread 2: dc[2] += da[2]*db[2] + da[3]*db[3];
到目前为止一切顺利。在for循环的第二次迭代中,stride为2,因此传递if测试的线程是线程0(仅)。
thread 0: dc[0] += da[0]*db[0] + da[2]*db[2];
但这没有意义,也不是我们想要的。我们想要的是:
dc[0] += dc[2];
所以它被打破了。我花了一些时间试着考虑如何在几个步骤中解决这个问题,但这对我来说只是减少了。如果用这段代码替换你的内核代码,我认为你会有很好的结果。它并不像你的代码那么多,但它是我能找到的最适合你所设想的所有情况的东西(即n&lt;最大线程块大小,使用单个块):
// CUDA kernel code
__global__ void sum_reduce(float* da, float* db, float* dc, int n)
{
int tid = threadIdx.x;
// do multiplication in parallel for full width of threads
dc[tid] = da[tid] * db[tid];
// wait for all threads to complete multiply step
__syncthreads();
int stride = blockDim.x;
while (stride > 1){
// handle odd step
if ((stride & 1) && (tid == 0)) dc[0] += dc[stride - 1];
// successively divide problem by 2
stride >>= 1;
// add each upper half element to each lower half element
if (tid < stride) dc[tid] += dc[tid + stride];
// wait for all threads to complete add step
__syncthreads();
}
}
请注意,我并没有真正使用n
参数。由于您使用n
个线程启动内核,因此blockDim.x
内置变量在这种情况下等于n
。