CUDA常量内存中的函数指针

CUDA常量内存中的函数指针,cuda,Cuda,在CUDA中尝试函数指针时,我发现了一些奇怪的运行时行为 目标 我的目标是让我的函数指针根据两个对象的内部属性选择要应用于两个对象的函数。 简而言之,我想用CUDA内核来模拟C++模板——而不必实际使用模板参数或代码>开关< /COD>子句,但是函数指针和类< /代码> /结构> 成员。 方法 使用一个属性(int-type)定义我的自定义对象struct customObj,该属性将模拟模板的参数 定义一组虚拟函数(Sum(),Subtract(),等等)以供选择 将要应用的函数列表(fun

在CUDA中尝试函数指针时,我发现了一些奇怪的运行时行为

目标
我的目标是让我的函数指针根据两个对象的内部属性选择要应用于两个对象的函数。 简而言之,我想用CUDA内核来模拟C++模板——而不必实际使用模板参数或代码>开关< /COD>子句,但是函数指针和<代码>类< /代码> /<代码>结构> <代码>成员。 方法

  • 使用一个属性(
    int-type
    )定义我的自定义对象
    struct customObj
    ,该属性将模拟模板的参数
  • 定义一组虚拟函数(
    Sum()
    Subtract()
    ,等等)以供选择
  • 将要应用的函数列表(
    functionsList
    )和要查找的相应
    type
    成员(
    first\u types
    second\u types
    )保存在
    \uu constant\uuuuu
    内存中,以便将function
    functionsList[i](obj1,obj2)
    应用于具有
    obj1.type==first\u types[i]的对象
    obj2.type==第二种类型[i]
工作代码
以下代码是在计算能力为3.0(GeForce GTX 670)的GPU上为使用CUDA 5.0的Linux x86_64编译的,并且可以正常工作

#include <stdio.h>
#include <iostream>
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, 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);
   }
}

struct customObj
{
  int type;
  double d;
  // Constructors
  __device__ __host__ customObj() {}
  __device__ __host__ customObj(const int& _type, const double& _d) : type(_type), d(_d) {}
};

typedef void (*function_t)(customObj&, customObj&);
// Define a bunch of functions
__host__ __device__ void Sum(customObj& obj1, customObj& obj2) {printf("Sum chosen! d1 + d2 = %f\n", obj1.d + obj2.d);}
__host__ __device__ void Subtract(customObj& obj1, customObj& obj2) {printf("Subtract chosen! d1 - d2 = %f\n", obj1.d - obj2.d);}
__host__ __device__ void Multiply(customObj& obj1, customObj& obj2) {printf("Multiply chosen! d1 * d2 = %f\n", obj1.d * obj2.d);}

#define ARRAYLENGTH 3
__constant__ int first_type[ARRAYLENGTH] = {1, 2, 3};
__constant__ int second_type[ARRAYLENGTH] = {1, 1, 2};
__constant__ function_t functionsList[ARRAYLENGTH] = {Sum, Sum, Subtract};

// Kernel to loop through functions list
__global__ void choosefunction(customObj obj1, customObj obj2) {
   int i = 0;
   function_t f = NULL;
   do {
     if ((obj1.type == first_type[i]) && (obj2.type == second_type[i])) {
       f = functionsList[i];
       break;
    }
    i++;
  } while (i < ARRAYLENGTH);
  if (f == NULL) printf("No possible interaction!\n");
  else f(obj1,obj2);
}

int main() {
  customObj obj1(1, 5.2), obj2(1, 2.6);
  choosefunction<<<1,1>>>(obj1, obj2);
  gpuErrchk(cudaPeekAtLastError());
  gpuErrchk(cudaDeviceSynchronize()); 

  return 0;
}
#包括
#包括
#定义gpuerchk(ans){gpuAssert((ans),_文件_,_行__)}
内联void gpuAssert(cudaError\u t代码,char*文件,int行,bool abort=true)
{
如果(代码!=cudaSuccess)
{
fprintf(标准,“GPUassert:%s%s%d\n”,cudaGetErrorString(代码)、文件、行);
如果(中止)退出(代码);
}
}
结构自定义对象
{
int型;
双d;
//建设者
__设备\主机\自定义对象()
__设备\uuuuuuuuuuuuuuuuu主机\uuuuuuuuuu自定义对象(常量int和类型,常量double和d):类型(\u类型),d(\u d){
};
typedef void(*function_t)(customObj&,customObj&);
//定义一组函数
__主机设备无效和(customObj&obj1,customObj&obj2){printf(“选择的和!d1+d2=%f\n,obj1.d+obj2.d);}
__主机uuu uuu设备uuuu无效减法(customObj&obj1,customObj&obj2){printf(“选择减法!d1-d2=%f\n”,obj1.d-obj2.d);}
__主机设备无效乘法(customObj&obj1,customObj&obj2){printf(“选择乘法!d1*d2=%f\n”,obj1.d*obj2.d);}
#定义阵列长度3
__常数_uuint first_type[ARRAYLENGTH]={1,2,3};
__常数_uuint second_type[ARRAYLENGTH]={1,1,2};
__常数函数列表[ARRAYLENGTH]={和,和,减};
//内核循环函数列表
__全局无效选择函数(customObj obj1、customObj obj2){
int i=0;
函数f=NULL;
做{
if((obj1.type==first_type[i])&(obj2.type==second_type[i])){
f=功能列表[i];
打破
}
i++;
}而(i<排列长度);
如果(f==NULL)printf(“没有可能的交互!\n”);
其他f(obj1、obj2);
}
int main(){
客户OBJ obj1(1,5.2),obj2(1,2.6);
选择功能(obj1、obj2);
gpuerchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());
返回0;
}
问题
我发现的问题是,一旦我替换了成员
int type
的数据类型以及相关的变量和函数(
\uuuuu常量\uuuuuuuu int first\u类型[…]
等等)。。。代码已编译但停止工作

  • 如果我将数据类型从
    int
    更改为
    char
    int8\t
    ,则内存检查器会在调用
    cudaDeviceSynchronize()
    时抛出
    错误4
  • 如果将数据类型更改为unsigned short int,则会出现硬件堆栈溢出

那么,在使用
\uuuuu常量\uuuuu
内存时,是否有人有类似的问题?我真的不知道发生了什么事。据我所知,
char
int8\t
是1字节长度的内置类型,而
int
的大小是4字节,所以可能是关于数据对齐,但我只是在这里猜测。此外,CUDA应该支持GPU上的函数指针,因为compute capability 2.0。对于
\uuuu constant\uuuu
内存中缺少的函数指针,是否有任何特殊约束?

我能够在64位RHEL 5.5上的CUDA 5.0上重现问题(错误4,未指定的启动失败),但在CUDA 6.0上没有


请更新/升级到CUDA 6。

我无法在使用CUDA 6的linux上重新解决此问题。这是我的例子。也许您应该使用一个唯一的typedef来修改代码,该typedef准确地显示您正在从
int
切换到其他类型的元素。