如何在CUDA中实现基本的C ++ 2D数组循环

时间:2013-08-20 16:17:45

标签: c++ vector matrix cuda parallel-processing

我对C ++编码很陌生,我目前正在尝试使用CUDA进行一些GPU计算。

基本上我有一个矩阵 A(N by N) ,还有几个向量 b 和的 X0 即可。 b和x0也有N个元素。

这是我试图实现的代码片段:

for (unsigned i=1;i<=N;i++){
    T sum = 0;
    for (unsigned j=1;j<=N;j++){
        sum += A[j][i]*x0[j];
    }
    v[i] = b[i] - sum;
}

其中 T 是一个模板变量(就我所知,可以分配一个双精度数。)

是否有可能将整个事物并行化,如果是这样,我将如何做到这一点?我也可以使用一些关于如何将这样的问题分解为块的线程,以及如何将2D从主机移动到设备并返回...

如果需要任何其他信息,请与我们联系。

编辑1:在查看CUBLAS并且没有走得太远之后,我决定压平我的矩阵并自己编写代码。我的第一个发现是我的cuda内核不喜欢使用双类型变量/数组[有人可以确认吗?]。

将所有内容转换为浮点数后,我编写的cuda内核看起来像这样:

__global__ void cudaMatTimesVect(float *p, float  *x0, float *v, float *sum, float *toSum, float *b, int N){

int idx = blockIdx.x * blockDim.x + threadIdx.x; // thread index

if (idx < N*N){
    toSum[idx] = p[idx] * x0[blockIdx.x];
}

__syncthreads();
if( idx-(blockIdx.x * blockDim.x) == 0){
    for(int i=0; i<blockDim.x; i++){
        sum[blockIdx.x] += toSum[idx+i];
    }

v[blockIdx.x] = b[blockIdx.x] - sum[blockIdx.x];
}

我不确定 syncthreads()命令是否会在尝试执行sum循环之前等待所有线程相乘。

以下是关于sum和仅在GPU上初始化的toSum数组的CPU代码片段:

float *d_sum;
float *d_toSum;
cudaError_t  cudaStatus;
...
// allocate toSum memory
cudaStatus = cudaMalloc(&d_toSum, N*N*sizeof(float));
if (cudaStatus != cudaSuccess){
    std::cout << "couldnt allocate device memory for d_toSum!" << std::endl;
    cudaFree(d_toSum);
}
// allocate sum mem on device
cudaStatus = cudaMalloc(&d_sum, N*sizeof(float));
if (cudaStatus != cudaSuccess){
    std::cout << "couldnt allocate device memory for d_sum" << std::endl;
    cudaFree(d_sum);
}

... 
...
// call the kernel
cudaMatTimesVect<<<N,N>>>(d_p, d_x0, d_v, d_sum, d_toSum, d_b, N);
...


cudaFree(d_toSum);
cudaFree(d_sum);

这是进行求和的最有效方法吗?

编辑2:我现在更改了代码以使用不同的块indcies来运行行计算。 上面的内核编译并运行,但v中的数组元素似乎越来越小而不是重新启动......

我仍然有兴趣了解为什么我不能使用双打以及如果我想使用&lt;来定义我的主机数组,我的代码需要如何更改? vector&gt;。

谢谢,

阿尔钦

1 个答案:

答案 0 :(得分:1)

您可以在cublas中解决此问题:

使用cublasSetVectorcublasSetMatrix

将数据复制到GPU

使用相应的Get functions复制结果。

矩阵向量乘法用gemv处理。矢量矢量减法用axpy处理。

cuda samples中提供了一个工作的cublas示例。

根据其他评论:   对于此问题,没有理由将数据分段为1D块。我推荐的是cublas。但是,如果您想查看其他代码示例,请查看vector add examplematrix multiply example

对于主机上的双下标矩阵,您应该将其展平,以便您可以使用单个(*)指针和索引来引用数据。无论您使用的是Cublas还是编写自己的代码,都是如此。

编辑:回复问题中的更新。 你发布的乘法代码对我来说看起来不像矩阵向量乘法,除非你的向量重复N次,以便它与矩阵的长度(NxN)相匹配。然后它似乎是正确的。

求和代码看起来不正确,而且,由于它不以任何方式依赖于idx所有线程都在做同样的事情。因此没有并行优势,我们通常不会以这种方式编写GPU代码。

你的向量减法代码似乎近似正确,除了你似乎在矩阵的整个长度(NxN)上做一个向量减法时矩阵向量乘法的结果应该只产生一个向量长度N。

如果此代码可以生成与相同数据集的序列代码匹配的结果,我会感到惊讶。您是否检查过它是否为非平凡数据集生成了正确的结果? (不要使用每个数字相同的数据集。)