【发布时间】:2015-10-20 02:18:51
【问题描述】:
我想在 CPU 上动态创建一个函数指针列表(使用从 main() 调用的某种 push_back() 方法)并将其复制到 GPU __constant__ 或 __device__ 数组,而不需要求助于静态__device__ 函数指针。我相信this question 与我的问题有关;但是,我的目标是迭代地创建 __host__ 函数指针数组,然后将其复制到 __constant__ 函数指针数组,而不是在声明时初始化后者。
具有静态函数指针(如 here 或 here 所示)的工作代码示例将是:
common.h:
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <iostream>
#define num_functions 3
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
// fptr_t: Pointer to void function that takes two integer lvalues
typedef void (*fptr_t)(int&, int&);
// some examples of void(int&, int&) functions...
__device__ void Add(int &a, int &b) {printf("Add... %i + %i = %i\n", a, b, a+b);}
__device__ void Subtract(int &a, int &b) {printf("Subtract... %i - %i = %i\n", a, b, a-b);}
__device__ void Multiply(int &a, int &b) {printf("Multiply... %i * %i = %i\n", a, b, a*b);}
// List of function pointers in device memory
__constant__ fptr_t constant_fList[num_functions];
// Kernel called from main(): choose the function to apply whose index is equal to thread ID
__global__ void kernel(int a, int b) {
fptr_t f;
if (threadIdx.x < num_functions) {
f = constant_fList[threadIdx.x];
f(a,b);
}
}
#endif
main.cu:
#include "common.h"
// Static device function pointers
__device__ fptr_t p_Add = Add;
__device__ fptr_t p_Sub = Subtract;
__device__ fptr_t p_Mul = Multiply;
// Load function list to constant memory
void loadList_staticpointers() {
fptr_t h_fList[num_functions];
gpuErrchk( cudaMemcpyFromSymbol(&h_fList[0], p_Add, sizeof(fptr_t)) );
gpuErrchk( cudaMemcpyFromSymbol(&h_fList[1], p_Sub, sizeof(fptr_t)) );
gpuErrchk( cudaMemcpyFromSymbol(&h_fList[2], p_Mul, sizeof(fptr_t)) );
gpuErrchk( cudaMemcpyToSymbol(constant_fList, h_fList, num_functions * sizeof(fptr_t)) );
}
int main() {
loadList_staticpointers();
int a = 12, b = 15;
kernel<<<1,3>>>(a, b);
gpuErrchk(cudaGetLastError());
gpuErrchk(cudaDeviceSynchronize());
return 0;
}
规格:GeForce GTX 670,编译为 -arch=sm_30,CUDA 6.5,Ubuntu 14.04
我希望避免使用静态设备函数指针,因为附加每个函数都需要在用户端进行代码维护 - 声明一个新的静态指针,如 p_Add 或 p_Mul,操作 void loadList_functionpointers() 等. 为了清楚起见,我正在尝试以下(崩溃)代码:
main_wrong.cu:
#include "common.h"
#include <vector>
// Global variable: list of function pointers in host memory
std::vector<fptr_t> vec_fList;
// Add function to functions list
void addFunc(fptr_t f) {vec_fList.push_back(f);}
// Upload the functions in the std::vector<fptr_t> to GPU memory
// Copies CPU-side pointers to constant_fList, therefore crashes on kernel call
void UploadVector() {
fptr_t* h_vpointer = vec_fList.data();
gpuErrchk( cudaMemcpyToSymbol(constant_fList, h_vpointer, vec_fList.size() * sizeof(fptr_t)) );
}
int main() {
addFunc(Add);
addFunc(Subtract);
addFunc(Multiply);
int a = 12, b = 15;
UploadVector();
kernel<<<1,3>>>(a, b); // Wrong to call a host-side function pointer from a kernel
gpuErrchk(cudaGetLastError());
gpuErrchk(cudaDeviceSynchronize());
return 0;
}
我的理解是函数指针指向主机地址被复制到GPU中,内核无法使用,函数@时需要指针指向GPU地址 987654339@ 被调用。使用设备端指针填充主机端数组对我来说适用于原始数据(请参阅this question),但不适用于函数指针。统一内存的简单尝试也失败了......到目前为止,我只发现静态设备端指针可以工作。没有其他方法可以将动态创建的 CPU 函数指针数组复制到 GPU 上吗?
【问题讨论】:
-
附带说明:为什么需要使用函数指针?你想用他们解决什么问题?
-
我正在开发用于粒子模拟的代码。粒子根据彼此的属性以不同的方式相互交互,因此必须动态确定应用于每个交互的函数。
-
这比在内核中使用
switch更好吗? -
内核中的
switch涉及在用户端对代码的操作 - 每次他们引入一个新函数(他们已经需要编码)时,都必须为switch。我不希望用户需要了解 CUDA 机制,而是为他们提供一些从main()调用的addFunc(f)机制,唯一的 C++ 代码将涉及f。 -
我明白了;用户在添加新功能时重新编译整个代码是否可行?然后您可以使用一些模板逻辑自动为您生成该开关。我也猜想这给了编译器更多优化代码的机会。如果您可以使用模板,是否可以升级到 CUDA 7 以启用 C++11?