我正在尝试一个项目,试图并行化并加速其他人设计的一些统计/数值计算脚本。在这个项目开始之前,我在编程方面是一个完全的新手(我更多的是分析数学类型),所以请原谅我任何随之而来的无知或完全的误解。他们使用以下函数生成矩阵:
double ** CreateMatrix(int m, int n)
{
int i;
double **A;
// pointer allocation to rows
A = (double **) malloc((size_t)((m*n)*sizeof(double)));
// allocate rows and set pointers
A[0] = (double *) malloc((size_t)((m*n)*sizeof(double)));
for(i=1; i<=m; i++){
A[i]=A[i-1] + n;
}
// return the pointer to array of pointers to rows
return A;
}
我并不热衷于重新设计矩阵对象的基本结构,因为他们已经围绕它设计了整个代码,所以我一直试图将这些结构传递给GPU,但是我读取分配内存并将指针复制到指针数组的1D线性内存在GPU上效率低下效率太低。我试图让这个最基本的例子起作用:
__global__ void MatrixMult(double *A, double *B, double *C, int N)
{
int col = blockDim.x*blockIdx.x + threadIdx.x;
int row = blockDim.y*blockIdx.y + threadIdx.y;
if( col < N && row < N){
C[col*N + row] = A[col*N + row] + B[col*N + row];
//C[col][row] = B[col][row] + A[col][row];
}
}
const int N = 5000;
int main()
{
double **h_A,**h_B, **h_C;
h_A = CreateMatrix(N,N);
h_B = CreateMatrix(N,N);
h_C = CreateMatrix(N,N);
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
h_A[i][j]=1;
h_B[i][j]=6;
h_C[i][j]=0;
}
}
size_t pitchA,pitchB,pitchC;
double *d_A,*d_B,*d_C;
cudaMallocPitch(&d_A, &pitchA, N*sizeof(double), N);
cudaMallocPitch(&d_B, &pitchB, N*sizeof(double), N);
cudaMallocPitch(&d_C, &pitchC, N*sizeof(double), N);
cudaMemcpy2D(d_A, pitchA, h_A, N*sizeof(double), N*sizeof(double), N, cudaMemcpyHostToDevice);
cudaMemcpy2D(d_B, pitchB, h_B, N*sizeof(double), N*sizeof(double), N, cudaMemcpyHostToDevice);
cudaMemcpy2D(d_C, pitchC, h_C, N*sizeof(double), N*sizeof(double), N, cudaMemcpyHostToDevice);
dim3 GridSize(250,250,1);
dim3 BlockSize(20,20,1);
MatrixMult<<<GridSize, BlockSize>>>(d_A,d_B,d_C,N);
cudaMemcpy2D(h_C, N*sizeof(double), d_C,pitchC, N*sizeof(double), N, cudaMemcpyDeviceToHost);
PrintMatrix(h_C,N,N);
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
}
问题是当我尝试使用PrintMatrix函数检查结果时出现段错误:
void PrintMatrix(double **A, int m, int n)
{
int i, j;
for(i=0; i<m; i++){
for(j=0; j<n; j++){
cout << A[i][j] << "\t";
}
cout << "\n";
}
}
我猜有一些微妙的记忆重新调整,我不理解。我想我的第一个问题是,是否可以将2D double**
对象作为1D double*
传递给设备,进行一些计算,然后将其复制回原来的原始设备主机上有double**
格式?如果是这样,有人可以告诉我我错过了什么吗?
答案 0 :(得分:3)
我相信你的CreateMatrix
已被破坏,但它可能正常运行(我下面的版本与你的版本略有不同,尽管你的版本可能有用)。但是,主机和设备之间的一般矩阵处理被破坏了。 cudaMemcpy2D
和cudaMallocPitch
实际上并不是用于处理双指针数组(**
),尽管它们的名称。查看the documentation。
但是,CreateMatrix
(适当修复)确实允许您的代码稍作修改并正常工作。 CreateMatrix
巧妙地允许在主机上进行双向订阅访问,同时确保基础数据是连续的。因此,我们可以使用A[0]
作为指针直接指向A
中的连续底层数据。这意味着我们可以使用普通cudaMalloc
和cudaMemcpy
。这是一个完整的例子:
#include <iostream>
#define MAT_DIM 32
#define T1_VAL 1
#define T2_VAL 6
double ** CreateMatrix(int m, int n)
{
int i;
double **A;
// pointer allocation to rows
A = (double **) malloc((size_t)(m*sizeof(double *)));
// allocate rows and set pointers
A[0] = (double *) malloc((size_t)((m*n)*sizeof(double)));
for(i=1; i<=m; i++){
A[i]=A[i-1] + n;
}
// return the pointer to array of pointers to rows
return A;
}
void PrintMatrix(double **A, int m, int n)
{
int i, j;
for(i=0; i<m; i++){
for(j=0; j<n; j++){
std::cout << A[i][j] << "\t";
}
std::cout << "\n";
}
}
int ValidateMatrix(double **A, int m, int n)
{
int i, j;
for(i=0; i<m; i++)
for(j=0; j<n; j++)
if (A[i][j] != (T1_VAL+T2_VAL)) {printf("mismatch at %d, %d, value: %f\n", i,j,A[i][j]); return 0;}
return 1;
}
__global__ void MatrixMult(double *A, double *B, double *C, int N)
{
int col = blockDim.x*blockIdx.x + threadIdx.x;
int row = blockDim.y*blockIdx.y + threadIdx.y;
if( (col < N) && (row < N)){
C[col*N + row] = A[col*N + row] + B[col*N + row];
//C[col][row] = B[col][row] + A[col][row];
}
}
const int N = MAT_DIM;
int main()
{
double **h_A,**h_B, **h_C;
h_A = CreateMatrix(N,N);
h_B = CreateMatrix(N,N);
h_C = CreateMatrix(N,N);
for(int i=0; i<N; i++){
for(int j=0; j<N; j++){
h_A[i][j]=T1_VAL;
h_B[i][j]=T2_VAL;
h_C[i][j]=0;
}
}
double *d_A,*d_B,*d_C;
cudaMalloc(&d_A, N*N*sizeof(double));
cudaMalloc(&d_B, N*N*sizeof(double));
cudaMalloc(&d_C, N*N*sizeof(double));
cudaMemcpy(d_A, h_A[0], N*N*sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B[0], N*N*sizeof(double), cudaMemcpyHostToDevice);
dim3 BlockSize(16,16);
dim3 GridSize((N+BlockSize.x-1)/BlockSize.x,(N+BlockSize.y-1)/BlockSize.y);
MatrixMult<<<GridSize, BlockSize>>>(d_A,d_B,d_C,N);
cudaMemcpy(h_C[0], d_C,N*N*sizeof(double),cudaMemcpyDeviceToHost);
//PrintMatrix(h_C,N,N);
if (!ValidateMatrix(h_C, N, N)) printf("Failure!\n");
else printf("Success!\n");
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
}
你的PrintMatrix
是segfaulting的近因是,从设备到主机的cudaMemcpy2D
操作覆盖了已经建立的指针数组,以h_C
为CreateMatrix
}}。如我所示,通过使用指向数组的单个指针来解决这个问题。
您的PrintMatrix
没有任何问题,如果您愿意,您应该可以取消注释。我只是不想查看大型矩阵的打印输出。
另外,您的MatrixMult
内核实际上添加了2个矩阵。我相信你知道的。