我是cuda的新手。我编写了一个内核来创建维度sizeXsize的单位矩阵(GPUsetIdentity)。在函数GPUfunctioncall中,我调用了我的内核。单位矩阵应存储在dDataInv中。但是当我将它复制回dataOut sizexsize时,所有值都为零。我知道,我在某个地方做了一些非常愚蠢的事情,但无法得到它,我是cuda的新手,如果有人能指出我的错误。谢谢。
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <fstream>
#include <iterator>
#include <sstream>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <stdlib.h>
#include <cuda_runtime.h>
#include "cuda.h"
#define BLOCKSIZE 16
using namespace std;
__global__ void GPUsetIdentity (float* matrix, int width)
{
int tx = threadIdx.x;
int bx = blockIdx.x;
int offset = bx * BLOCKSIZE + tx;
matrix[offset + width * offset] = 1;
}
void print_matrix_host(float* A , int nr_rows_A, int nr_cols_A) {
for(int i = 0; i < nr_rows_A; ++i){
for(int j = 0; j < nr_cols_A; ++j){
std::cout << A[i * nr_rows_A + j ] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int GPUfunctioncall (float* hDataOut, int size){
float *dDataInv;
cudaMalloc ((void **) &dDataInv, size);
cudaMemset ((void *) dDataInv, 0, size);
dim3 idyThreads (BLOCKSIZE);
dim3 idyBlocks (size / BLOCKSIZE);
GPUsetIdentity <<< idyBlocks, idyThreads >>> (dDataInv, size);
cudaThreadSynchronize ();
cudaMemcpy ((void *) hDataOut, (void *) dDataInv, size, cudaMemcpyDeviceToHost);
cudaFree (dDataInv);
return 0;
}
int main()
{
int size = 4;
float* dataOut;
dataOut = new float[size*size];
GPUfunctioncall(dataOut, size);
print_matrix_host(dataOut, size, size);
}
答案 0 :(得分:1)
每当您遇到CUDA代码时遇到问题,最好使用proper cuda error checking。您还可以使用cuda-memcheck
运行代码,以快速了解是否存在任何错误。
使用这些方法中的任何一种,您都会在内核启动时发现“无效的配置错误”。这通常意味着<<< >>>
语法中的参数不正确。当您遇到这种类型的错误时,只需打印出这些值就可能表明存在问题。
在您的情况下,这行代码:
dim3 idyBlocks (size / BLOCKSIZE);
当0
为4且idyBlocks
为16时,会导致size
的值为BLOCKSIZE
。因此,您要求内核启动0个非法的块。因此,您的内核未运行,结果不符合您的预期。
有多种方法可以解决这个问题,其中许多方法都涉及检测此情况,并在size
无法被BLOCKSIZE
整除时添加“额外阻止”。使用这种方法,我们可能会启动“额外线程”,因此我们必须在内核中包含一个“线程检查”,以防止那些额外的线程做任何事情(例如访问数组越界)。为此,我们经常需要知道内核中的预期大小,并且我们可以将此值作为额外的内核参数传递。
您在处理设备变量时也遇到了一些错误。以下代码:
dataOut = new float[size*size];
为尺寸size
的方阵矩阵分配足够的空间。但是以下代码:
cudaMalloc ((void **) &dDataInv, size);
仅为size
字节分配足够的空间。您希望size*size*sizeof(float)
代替size
,而您希望在以下cudaMemset
和cudaMemcpy
操作中使用cudaMalloc
。 cudaMemset
,cudaMemcpy
和malloc
需要字节中的尺寸参数,就像memset
,memcpy
和{{1}一样}。您在使用cudaMemset
和cudaMemcpy
时也会发现此错误。
以下代码有这些修改,似乎对我有效:
$ cat t580.cu
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#define BLOCKSIZE 16
using namespace std;
__global__ void GPUsetIdentity (float* matrix, int width, int size)
{
int tx = threadIdx.x;
int bx = blockIdx.x;
int offset = bx * BLOCKSIZE + tx;
if (tx < size)
matrix[offset + width * offset] = 1;
}
void print_matrix_host(float* A , int nr_rows_A, int nr_cols_A) {
for(int i = 0; i < nr_rows_A; ++i){
for(int j = 0; j < nr_cols_A; ++j){
std::cout << A[i * nr_rows_A + j ] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int GPUfunctioncall (float* hDataOut, int size){
float *dDataInv;
cudaMalloc ((void **) &dDataInv, size*size*sizeof(float));
cudaMemset ((void *) dDataInv, 0, size*size*sizeof(float));
dim3 idyThreads (BLOCKSIZE);
int num_blocks = size/BLOCKSIZE + (size%BLOCKSIZE)?1:0;
dim3 idyBlocks (num_blocks);
GPUsetIdentity <<< idyBlocks, idyThreads >>> (dDataInv, size, size);
cudaThreadSynchronize ();
cudaMemcpy ((void *) hDataOut, (void *) dDataInv, size*size*sizeof(float), cudaMemcpyDeviceToHost);
cudaFree (dDataInv);
return 0;
}
int main()
{
int size = 4;
float* dataOut;
dataOut = new float[size*size];
GPUfunctioncall(dataOut, size);
print_matrix_host(dataOut, size, size);
}
$ nvcc -arch=sm_20 -o t580 t580.cu
$ cuda-memcheck ./t580
========= CUDA-MEMCHECK
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
========= ERROR SUMMARY: 0 errors
$
请注意,将size
两次传递给内核可能是多余的。对于这个特定的例子,我们可以很容易地使用width
参数来进行内核“线程检查”。但出于教育目的,我选择将其作为单独的参数调用,因为在一般情况下,您通常会将其作为单独的参数传递给您编写的其他内核。
最后,请注意cudaThreadSynchronize()
已弃用,而应替换为cudaDeviceSynchronize()
。在这个特定的例子中,niether实际上是必需的,因为下一个cudaMemcpy
操作将强制进行相同类型的同步,但是如果你决定将cuda错误检查添加到你的代码中,你可以使用它(推荐)。