我正在尝试在cuda的内核函数中使用动态3D数组参数,但我做得不好。
__global__ void kernel ( 3D array pointer )
{
// do something
}
int main()
{
const int NUM_OF_ARRAY;
const int ROW;
const int CAL;
int arr[NUM_OF_ARRAY][ROW][CAL];
// Maybe I should use cudaMalloc3D or cudaMalloc3DArray
dim3 grid( , , ,);
dim3 block( , , , );
kernel <<< grid, block >>> ( ? );
}
我看到罗伯特对sending 3d array to CUDA kernel的回答,但我认为我的情况略有不同。
如果在运行时确定了数组的行和cal,我如何在cuda中分配该内存并将该指针指向内核函数?
我尝试使用cudaMalloc3D或cudaMalloc3DArray,但我不能好,因为我以前从未使用过。
任何人都可以使用动态3D数组参数显示简单示例吗?
对我有帮助。感谢。
答案 0 :(得分:2)
由于上一个链接答案和其他地方建议的所有原因,这不一定是处理3D阵列的好方法。更好的方法是展平数组并使用指针算法来模拟3D访问。
但只是为了证明上一个示例并不需要是硬编码维度,这里修改了示例以显示变量(运行时)维度用法:
#include <iostream>
inline void GPUassert(cudaError_t code, char * file, int line, bool Abort=true)
{
if (code != 0) {
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code),file,line);
if (Abort) exit(code);
}
}
#define GPUerrchk(ans) { GPUassert((ans), __FILE__, __LINE__); }
__global__ void doSmth(int*** a, int sz_x, int sz_y, int sz_z) {
for(int i=0; i<sz_z; i++)
for(int j=0; j<sz_y; j++)
for(int k=0; k<sz_x; k++)
a[i][j][k]=i-j+k;
}
int main() {
unsigned sx;
unsigned sy;
unsigned sz;
std::cout << std::endl << "Enter x dimension (3rd subscript): " ;
std::cin >> sx;
std::cout << std::endl << "Enter y dimension (2nd subscript): " ;
std::cin >> sy;
std::cout << std::endl << "Enter z dimension (1st subscript): " ;
std::cin >> sz;
int*** h_c = (int***) malloc(sz*sizeof(int**));
for(int i=0; i<sz; i++) {
h_c[i] = (int**) malloc(sy*sizeof(int*));
for(int j=0; j<sy; j++)
GPUerrchk(cudaMalloc((void**)&h_c[i][j],sx*sizeof(int)));
}
int ***h_c1 = (int ***) malloc(sz*sizeof(int **));
for (int i=0; i<sz; i++){
GPUerrchk(cudaMalloc((void***)&(h_c1[i]), sy*sizeof(int*)));
GPUerrchk(cudaMemcpy(h_c1[i], h_c[i], sy*sizeof(int*), cudaMemcpyHostToDevice));
}
int*** d_c;
GPUerrchk(cudaMalloc((void****)&d_c,sz*sizeof(int**)));
GPUerrchk(cudaMemcpy(d_c,h_c1,sz*sizeof(int**),cudaMemcpyHostToDevice));
doSmth<<<1,1>>>(d_c, sx, sy, sz);
GPUerrchk(cudaPeekAtLastError());
int res[sz][sy][sx];
for(int i=0; i<sz; i++)
for(int j=0; j<sy; j++)
GPUerrchk(cudaMemcpy(&res[i][j][0], h_c[i][j],sx*sizeof(int),cudaMemcpyDeviceToHost));
std::cout << std::endl;
for(int i=0; i<sz; i++)
for(int j=0; j<sy; j++)
for(int k=0; k<sx; k++)
printf("[%d][%d][%d]=%d\n",i,j,k,res[i][j][k]);
}
我已将内核存储的数据修改为i-j+k
而不是i+j+k
。此外,我已经为下标创建了[z][y][x]
顺序,因为这将建议使用线程索引计算安排,例如[threadIdx.z][threadIdx.y][threadIdx.x]
,这将最有利于合并访问。但是,由于指针追逐以解析数据的最终位置,内核中的这种类型的多下标数组仍然往往效率低下。