我用CUDA写了一个点积产品代码来计算两个双向量的点积。内核由N个线程(N <1024)1块调用。但它无法给出正确的结果。我无法理解。
__global__ void dotthread(double* a, double *b,double *sum, int N)
{
int tid = threadIdx.x;
sum[0] = sum[0]+a[tid] * b[tid]; //every thread write to the sum[0]
__syncthreads();
}
答案 0 :(得分:1)
让我们看看你的三行代码中的两行:
sum[0] = sum[0]+a[tid] * b[tid]; //every thread write to the sum[0]
__syncthreads();
第一行包含记忆竞赛。块中的每个线程将同时尝试写入sum [0]。 cuda执行模型中没有任何内容可以阻止这种情况发生。没有自动序列化或内存保护可以阻止此行为。
第二行是指令障碍。这意味着线程的每个经线都将被阻塞,直到线程的每个经线都到达屏障。它对先前的指令没有任何影响,它对内存一致性或代码发出的任何内存事务的行为都没有任何影响。
你写的代码是不可逆转的。执行此类操作的规范方法是通过并行缩减。有许多不同的方法可以做到这一点。它可能是GPU描述和描述最多的并行算法。你已经安装了CUDA工具包,你已经有了一个完整的工作示例和一个描述算法的综合论文,因为它将使用共享内存实现。我建议你研究一下。
你可以看到使用共享内存here的点积的(几乎)工作实现,我建议你研究它。您还可以在库中找到并行块缩减的最佳实现,例如cub
答案 1 :(得分:-1)
我写了两个版本的dot产品程序。第一个使用atomiAdd函数,第二个为每个块分配一个共享变量。 计算时间分别为3.33 ms和0.19 ms,相比之下,还原点积和单线点积为0.17 ms和411.43 ms。
GPU Device 0: "GeForce GTX 1070 Ti" with compute capability 6.1
2000000flow array allocated 2147483647
naive elapsedTimeIn Ms 411.437042 Ms
sum is 6.2831853071e+06
thread atomic add elapsedTimeIn Ms 3.3371520042 Ms
sum is 6.2831853071e+06
cache reduction elapsedTimeIn Ms 0.1764480025 Ms
sum is 6.2831853072e+06
cache atomicadd elapsedTimeIn Ms 0.1914239973 Ms
sum is 6.2831853072e+06
__global__ void dotatomicAdd(double* a, double *b,double *sum, int N)
{
int tid = blockDim.x * blockIdx.x + threadIdx.x;
while (tid < N){
double t=a[tid] * b[tid];
atomicAdd(sum,t);
tid+=blockDim.x * gridDim.x;
}
}
__global__ void dotcache(double* a, double *b,double *c, int N)
{
__shared__ double cache;
int tid = threadIdx.x + blockIdx.x * blockDim.x;
int cacheIndex = threadIdx.x;
double temp = 0.0;
cache=0.0;
__syncthreads();
while (tid < N) {
temp += a[tid] * b[tid];
tid += blockDim.x * gridDim.x;
}
atomicAdd(&cache,temp);
__syncthreads();
if (cacheIndex == 0) c[blockIdx.x] = cache;
}