嗨,我正在迈出CUDA技术的第一步,但我认为我做不到。
我试图通过向量乘以二维数组,但有些东西不起作用
以下是我想弄清楚的代码:
#include <stdio.h>
#include <stdlib.h>
#define N 2
__global__ void Multiply(int A[N][N], int B[N], int C[N]){
int i = threadIdx.x;
int j = threadIdx.y;
int sum = A[i][j] * B[j];
C[i]= sum;
printf("%d,%d ", sum, C[i]);
}
int main(){
int A[N][N] ={ {1,1},
{1,1}
};
int B[N] = {4,6};
int C[N] = {0,0};
int (*aA)[N], (*aB), (*aC);
cudaMalloc((void**)&aA, (N*N)*sizeof(int));
cudaMalloc((void**)&aB, (N)*sizeof(int));
cudaMalloc((void**)&aC, (N)*sizeof(int));
cudaMemcpy(aA, A, (N*N)*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(aB, B, (N)*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(aC, C, (N)*sizeof(int), cudaMemcpyHostToDevice);
int numBlocks = 1;
dim3 threadsPerBlock(N,N);
Multiply<<<numBlocks,threadsPerBlock>>>(aA,aB,aC);
cudaMemcpy(C, aC, (N)*sizeof(int), cudaMemcpyDeviceToHost);
cudaFree(aA);
cudaFree(aB);
cudaFree(aC);
printf("\n");
system("pause");
}
在这种情况下,输出为:4,6 4,6 6,6 6,6所以基本上总和i给出正确的值,但C [i]总是返回6,尽管有分配的总和值。
我做错了什么?
答案 0 :(得分:1)
每当您遇到CUDA代码时遇到问题,最好使用proper cuda error checking并使用cuda-memcheck
运行代码。这只是我做的锅炉声明。在这种情况下,它实际上不会显示您所显示的代码的问题。
正如在现在删除的答案中已经指出的那样,你实际上并没有在一起总结任何东西。即使你有一个名为sum
的变量,它实际上并不是任何东西的总和,并且你的内核代码中没有+
或求和操作。你不是在编写一个可以将任何东西加在一起的内核。
为了产生正确的结果,您的内核依赖于合作让多个线程更新单个位置(C[i]
)。但是,这需要线程之间的一些协调。如果没有任何协调,您将使线程处于竞争状态,并且结果将是不可预测的。我们可以使用a parallel reduction对此进行排序,将每个单独线程的部分产品加在一起,或者为了简单起见,我们可以使用atomicAdd
operation来强制线程更新(添加到C[i]
一个一个,所以他们不会互相踩踏。因此,使用atomicAdd
还可以提供必要的添加(+
)操作,这在内核中是不存在的。
这是一个工作代码,其中涉及第2项和第3项。您可以使用cuda-memcheck
运行它来验证行为正确性,即使它没有明确的错误检查:
$ cat t1037.cu
#include <stdio.h>
#include <stdlib.h>
#define N 2
__global__ void Multiply(int A[N][N], int B[N], int C[N]){
int i = threadIdx.x;
int j = threadIdx.y;
int product = A[i][j] * B[j];
atomicAdd(C+i, product);
// printf("%d,%d ", product, C[i]);
}
int main(){
int A[N][N] ={ {1,1},
{1,1}
};
int B[N] = {4,6};
int C[N] = {0,0};
int (*aA)[N], (*aB), (*aC), i;
cudaMalloc((void**)&aA, (N*N)*sizeof(int));
cudaMalloc((void**)&aB, (N)*sizeof(int));
cudaMalloc((void**)&aC, (N)*sizeof(int));
cudaMemcpy(aA, A, (N*N)*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(aB, B, (N)*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(aC, C, (N)*sizeof(int), cudaMemcpyHostToDevice);
int numBlocks = 1;
dim3 threadsPerBlock(N,N);
Multiply<<<numBlocks,threadsPerBlock>>>(aA,aB,aC);
cudaMemcpy(C, aC, (N)*sizeof(int), cudaMemcpyDeviceToHost);
for (i=0; i<N; i++){
printf("C[%d] = %d\n",i,C[i]);
}
cudaFree(aA);
cudaFree(aB);
cudaFree(aC);
printf("\n");
}
$ nvcc -o t1037 t1037.cu
$ cuda-memcheck ./t1037
========= CUDA-MEMCHECK
C[0] = 10
C[1] = 10
========= ERROR SUMMARY: 0 errors
$