我是C ++编码的新手,目前正在尝试使用CUDA进行一些GPU计算。

基本上,我有一个矩阵A(N×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是模板变量(据我所知,可以分配为double)。

是否有可能使整个事情并行化,如果可以的话,我将如何做到这一点?我还可以使用一些指针来解决一般将此类问题的线程分解为块,以及如何将2D从主机移至设备再移回...

如果需要任何其他信息,请告诉我。

编辑1:在研究了CUBLAS并走得不远时,Ive决定展平矩阵并自己编写代码。我的第一个发现是我的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()命令是否将等待所有线程相乘。

以下是有关仅在GPU上初始化的sum和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:我现在已更改代码以使用不同的块索引来运行行计算。
上面的内核可以编译并运行,但是v中的数组元素似乎越来越小而不是重新启动...

我仍然很想了解为什么我不能使用双精度,以及如果要使用定义主机数组,我的代码需要如何更改。

谢谢,

Armen

最佳答案

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

使用cublasSetVectorcublasSetMatrix将数据复制到GPU

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

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

cuda samples中提供了有效的cublas示例。

基于其他注释:
  没有理由将数据分割为1D块。我推荐cublas。但是,如果要查看其他代码示例,请查看vector add examplematrix multiply example

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

编辑:响应问题中的更新。
在我看来,您发布的乘法代码不像矩阵向量乘法,除非您将向量的长度复制了N次,以使其与矩阵的长度(NxN)相匹配。然后,这似乎是正确的。

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

您的向量减法代码似乎是正确的,只是当矩阵向量乘积的结果只应产生长度为N的向量时,您似乎正在对矩阵的整个长度(NxN)进行向量减法。

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

关于c++ - 如何在CUDA中实现基本的C++ 2D数组循环,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18340111/

10-10 07:40