我是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中解决此问题:
使用cublasSetVector或cublasSetMatrix将数据复制到GPU
使用相应的Get
functions将结果复制回去。
矩阵向量乘法用gemv处理。向量-向量相减用axpy处理。
cuda samples中提供了有效的cublas示例。
基于其他注释:
没有理由将数据分割为1D块。我推荐cublas。但是,如果要查看其他代码示例,请查看vector add example和matrix multiply example。
对于主机上的双下标矩阵,应将其展平,以便可以使用单个(*
)指针和索引来引用数据。无论您是使用cublas还是编写自己的代码,都是如此。
编辑:响应问题中的更新。
在我看来,您发布的乘法代码不像矩阵向量乘法,除非您将向量的长度复制了N次,以使其与矩阵的长度(NxN)相匹配。然后,这似乎是正确的。
求和代码看起来不正确,此外,由于它不以任何方式依赖idx
,因此所有线程都在做完全相同的事情。因此,那里没有并行优势,而且我们通常不会以这种方式编写GPU代码。
您的向量减法代码似乎是正确的,只是当矩阵向量乘积的结果只应产生长度为N的向量时,您似乎正在对矩阵的整个长度(NxN)进行向量减法。
如果此代码可以产生与您的相同数据集的串行代码相匹配的结果,我会感到惊讶。您是否检查过它对于非平凡的数据集产生了正确的结果? (不要使用每个数字都相同的数据集。)
关于c++ - 如何在CUDA中实现基本的C++ 2D数组循环,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18340111/