[英]CUDA: Allocating 1d device memory to copy 2d pointer-to-pointer host array to and from GPU
我正在做一個項目,試圖並行化和加速其他人設計的一些統計/數字計算腳本。 在這個項目開始之前,我是編程的新手(我更是解析數學類型),所以請原諒我對它的任何無知或完全誤解。 他們正在使用以下函數來生成矩陣:
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,但作為一維線性內存,因為我讀過分配在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**
格式? 如果是這樣,有人可以告訴我我所缺少的嗎?
我相信您的CreateMatrix
已損壞,但是它可能是功能正常的(我下面的版本與您的版本略有不同,盡管您的版本可能會起作用)。 但是,主機和設備之間的常規矩陣處理已損壞。 盡管使用了cudaMemcpy2D
和cudaMallocPitch
的名稱,但它們實際上並不用於處理雙指針數組( **
)。 查看文檔 。
但是,您的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
的最接近的原因是,從設備到主機的cudaMemcpy2D
操作正在覆蓋由CreateMatrix
建立以建立到h_C
索引的指針數組。 如我所示,這是通過使用單個指向數組的指針來解決的。
您的PrintMatrix
沒什么問題,並且您可以取消注釋。 我只是不想查看大型矩陣的打印輸出。
MatrixMult
,您的MatrixMult
內核實際上是在添加2個矩陣。 我確定你知道。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.