Struct 将带有函数指针的结构复制到设备
我有一个包含线性函数参数的结构,以及函数本身。我要做的是将这个结构复制到设备上,然后计算线性函数。下面的例子没有意义,但足以描述我遇到的困难:Struct 将带有函数指针的结构复制到设备,struct,cuda,gpu,Struct,Cuda,Gpu,我有一个包含线性函数参数的结构,以及函数本身。我要做的是将这个结构复制到设备上,然后计算线性函数。下面的例子没有意义,但足以描述我遇到的困难: struct model { double* params; double (*func)(double*, double); }; 我不知道如何将这个结构复制到设备上 以下是我的职能: 初始化函数 评价函数 实际功能 在内核中调用的函数 内核本身 \uuuuu全局\uuuuuu无效内核(双*数组,模型*d\u线性模型,int N) { int idx
struct model
{
double* params;
double (*func)(double*, double);
};
我不知道如何将这个结构复制到设备上
以下是我的职能:
初始化函数
评价函数
实际功能
在内核中调用的函数
内核本身
\uuuuu全局\uuuuuu无效内核(双*数组,模型*d\u线性模型,int N)
{
int idx=blockIdx.x*blockDim.x+threadIdx.x;
if(idx
我知道如何将数组从主机复制到设备,但我不知道如何为这个包含函数的具体结构执行此操作
main中的内核调用如下所示:
int block_size = 4;
int n_blocks = N_array/block_size + (N_array % block_size == 0 ? 0:1);
kernel<<<n_blocks, block_size>>>(device_array, d_linear_model, N_array);
int block_size=4;
int n_blocks=n_数组/块大小+(n_数组%block大小==0?0:1);
内核(设备_阵列、d_线性_模型、N_阵列);
> p>您已经概述了两个我认为比初学者级CUDA编程更难的项目:
设备函数指针的使用
“深度复制”操作(在模型
结构中嵌入的参数
指针上)
这两个主题已在其他问题中介绍。例如,讨论深度复制操作-当数据结构具有指向其他数据的嵌入式指针时。并链接到有关设备函数指针使用的各种资源
但我会继续为你的案例提供一个可能的解决方案。您的大多数代码都可以按原样使用(至少出于演示目的)。如前所述,您的模型
结构将面临两个挑战:
struct model
{
double* params; // requires a "deep copy" operation
double (*func)(double*, double); // requires special handling for device function pointers
};
因此,尽管您的大多数代码都是可用的,但“init”函数不是。这可能适用于主机实现,但不适用于设备实现
深度复制操作要求我们复制整个结构,再加上单独复制嵌入指针指向的数据,再加上单独复制或“修复”嵌入指针本身
设备函数指针的使用受到以下事实的限制:我们无法在主机代码中获取实际的设备函数指针,这在CUDA中是非法的。因此,一种可能的解决方案是使用\uuuuu device\uuuuu
构造来“捕获”设备函数指针,然后在主机代码中执行cudamemcpyfromsymsymbol
操作,以检索设备函数指针的数值,然后可以以普通方式移动指针
下面是一个基于您所展示内容的工作示例,演示了上述两个概念。我还没有创建“device init”函数,但所有需要创建的代码都在main
函数中。一旦你掌握了这些概念,你可以从下面的主函数中提取任何你想要的代码,如果你想创建一个的话,你可以将它制作成你的“device init”函数
下面是一个成功的例子:
$ cat t968.cu
#include <iostream>
#define NUM_PARAMS 2
#define ARR_SIZE 1
#define nTPB 256
struct model
{
double* params;
double (*func)(double*, double);
};
// init function for struct model -- not using this for device operations
__host__ void model_init(model* m, double* params, double(*func)(double*,double))
{
if(m)
{
m->params = params;
m->func = func;
}
}
__device__ double model_evaluate(model* m, double x)
{
if(m)
{
return m->func(m->params, x);
}
return 0.0;
}
__host__ __device__ double linear_function(double* params, double x)
{
return params[0] + params[1] * x;
}
__device__ double compute(model *d_linear_model)
{
return model_evaluate(d_linear_model,1.0);
}
__global__ void kernel(double *array, model *d_linear_model, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
{
array[idx] = compute(d_linear_model);
}
}
__device__ double (*linear_function_ptr)(double*, double) = linear_function;
int main(){
// grab function pointer from device code
double (*my_fp)(double*, double);
cudaMemcpyFromSymbol(&my_fp, linear_function_ptr, sizeof(void *));
// setup model
model my_model;
my_model.params = new double[NUM_PARAMS];
my_model.params[0] = 1.0;
my_model.params[1] = 2.0;
my_model.func = my_fp;
// setup for device copy of model
model *d_model;
cudaMalloc(&d_model, sizeof(model));
// setup "deep copy" for params
double *d_params;
cudaMalloc(&d_params, NUM_PARAMS*sizeof(double));
cudaMemcpy(d_params, my_model.params, NUM_PARAMS*sizeof(double), cudaMemcpyHostToDevice);
// copy model to device
cudaMemcpy(d_model, &my_model, sizeof(model), cudaMemcpyHostToDevice);
// fixup device params pointer in device model
cudaMemcpy(&(d_model->params), &d_params, sizeof(double *), cudaMemcpyHostToDevice);
// run test
double *d_array, *h_array;
cudaMalloc(&d_array, ARR_SIZE*sizeof(double));
h_array = new double[ARR_SIZE];
for (int i = 0; i < ARR_SIZE; i++) h_array[i] = i;
cudaMemcpy(d_array, h_array, ARR_SIZE*sizeof(double), cudaMemcpyHostToDevice);
kernel<<<(ARR_SIZE+nTPB-1)/nTPB,nTPB>>>(d_array, d_model, ARR_SIZE);
cudaMemcpy(h_array, d_array, ARR_SIZE*sizeof(double), cudaMemcpyDeviceToHost);
std::cout << "Results: " << std::endl;
for (int i = 0; i < ARR_SIZE; i++) std::cout << h_array[i] << " ";
std::cout << std::endl;
return 0;
}
$ nvcc -o t968 t968.cu
$ cuda-memcheck ./t968
========= CUDA-MEMCHECK
Results:
3
========= ERROR SUMMARY: 0 errors
$
$cat t968.cu
#包括
#定义NUM_参数2
#定义ARR_大小1
#定义nTPB 256
结构模型
{
双*参数;
双(*func)(双*,双);
};
//结构模型的init函数--不用于设备操作
__host_uuuu void model_uinit(model*m,double*参数,double(*func)(double*,double))
{
如果(m)
{
m->params=params;
m->func=func;
}
}
__设备?双模型?评估(模型*m,双x)
{
如果(m)
{
返回m->func(m->params,x);
}
返回0.0;
}
__主机设备双线性函数(双*参数,双x)
{
返回参数[0]+参数[1]*x;
}
__设备双计算(模型*d线性模型)
{
收益模型(d_线性模型,1.0);
}
__全局无效内核(双*数组,模型*d\u线性模型,int N)
{
int idx=blockIdx.x*blockDim.x+threadIdx.x;
if(idxparams),&d_params,sizeof(double*),cudaMemcpyHostToDevice);
//运行测试
双*d_数组,*h_数组;
cudaMalloc(&d_数组,ARR_大小*sizeof(双精度));
h_数组=新的双精度[ARR_SIZE];
对于(int i=0;i Std::Couth你已经概述了两个我认为比初学者级CUDA编程更难的项目:
设备函数指针的使用
“深度复制”操作(在模型
结构中嵌入的参数
指针上)
这两个主题已在其他问题中讨论。例如,讨论深度复制操作-当数据结构嵌入指向其他数据的指针时。以及有关设备函数指针使用的各种资源的链接
但是我会继续为您发布的案例提供一个可能的解决方案。您的大多数代码都是可用的(至少用于演示目的)。正如前面提到的,您的模型
__device__ double compute(model *d_linear_model)
{
return model_evaluate(d_linear_model,1.0);
}
__global__ void kernel(double *array, model *d_linear_model, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
{
array[idx] = compute(d_linear_model);
}
}
int block_size = 4;
int n_blocks = N_array/block_size + (N_array % block_size == 0 ? 0:1);
kernel<<<n_blocks, block_size>>>(device_array, d_linear_model, N_array);
struct model
{
double* params; // requires a "deep copy" operation
double (*func)(double*, double); // requires special handling for device function pointers
};
$ cat t968.cu
#include <iostream>
#define NUM_PARAMS 2
#define ARR_SIZE 1
#define nTPB 256
struct model
{
double* params;
double (*func)(double*, double);
};
// init function for struct model -- not using this for device operations
__host__ void model_init(model* m, double* params, double(*func)(double*,double))
{
if(m)
{
m->params = params;
m->func = func;
}
}
__device__ double model_evaluate(model* m, double x)
{
if(m)
{
return m->func(m->params, x);
}
return 0.0;
}
__host__ __device__ double linear_function(double* params, double x)
{
return params[0] + params[1] * x;
}
__device__ double compute(model *d_linear_model)
{
return model_evaluate(d_linear_model,1.0);
}
__global__ void kernel(double *array, model *d_linear_model, int N)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N)
{
array[idx] = compute(d_linear_model);
}
}
__device__ double (*linear_function_ptr)(double*, double) = linear_function;
int main(){
// grab function pointer from device code
double (*my_fp)(double*, double);
cudaMemcpyFromSymbol(&my_fp, linear_function_ptr, sizeof(void *));
// setup model
model my_model;
my_model.params = new double[NUM_PARAMS];
my_model.params[0] = 1.0;
my_model.params[1] = 2.0;
my_model.func = my_fp;
// setup for device copy of model
model *d_model;
cudaMalloc(&d_model, sizeof(model));
// setup "deep copy" for params
double *d_params;
cudaMalloc(&d_params, NUM_PARAMS*sizeof(double));
cudaMemcpy(d_params, my_model.params, NUM_PARAMS*sizeof(double), cudaMemcpyHostToDevice);
// copy model to device
cudaMemcpy(d_model, &my_model, sizeof(model), cudaMemcpyHostToDevice);
// fixup device params pointer in device model
cudaMemcpy(&(d_model->params), &d_params, sizeof(double *), cudaMemcpyHostToDevice);
// run test
double *d_array, *h_array;
cudaMalloc(&d_array, ARR_SIZE*sizeof(double));
h_array = new double[ARR_SIZE];
for (int i = 0; i < ARR_SIZE; i++) h_array[i] = i;
cudaMemcpy(d_array, h_array, ARR_SIZE*sizeof(double), cudaMemcpyHostToDevice);
kernel<<<(ARR_SIZE+nTPB-1)/nTPB,nTPB>>>(d_array, d_model, ARR_SIZE);
cudaMemcpy(h_array, d_array, ARR_SIZE*sizeof(double), cudaMemcpyDeviceToHost);
std::cout << "Results: " << std::endl;
for (int i = 0; i < ARR_SIZE; i++) std::cout << h_array[i] << " ";
std::cout << std::endl;
return 0;
}
$ nvcc -o t968 t968.cu
$ cuda-memcheck ./t968
========= CUDA-MEMCHECK
Results:
3
========= ERROR SUMMARY: 0 errors
$