如何实现设备端CUDA虚拟功能?

如何实现设备端CUDA虚拟功能?,cuda,virtual-functions,Cuda,Virtual Functions,我看到CUDA不允许将带有虚拟函数的类传递到内核函数中。有没有解决这个限制的办法 我真的希望能够在内核函数中使用多态性 谢谢 罗伯特·克罗维拉评论中最重要的部分是: 这些对象只需在设备上创建即可 记住这一点,我正在处理这样一种情况:我有一个抽象的类函数,然后它的一些实现封装了不同的函数及其求值。这是我的代码的简化版本,我是如何在我的情况下实现多态性的,但我并不是说不能做得更好。。。这将有助于您了解以下内容: class Function { public: __device__ Func

我看到CUDA不允许将带有虚拟函数的类传递到内核函数中。有没有解决这个限制的办法

我真的希望能够在内核函数中使用多态性


谢谢

罗伯特·克罗维拉评论中最重要的部分是:

这些对象只需在设备上创建即可

记住这一点,我正在处理这样一种情况:我有一个抽象的
类函数
,然后它的一些实现封装了不同的函数及其求值。这是我的代码的简化版本,我是如何在我的情况下实现多态性的,但我并不是说不能做得更好。。。这将有助于您了解以下内容:

class Function
{
public:
    __device__ Function() {}
    __device__ virtual ~Function() {}
    __device__ virtual void Evaluate(const real* __restrict__ positions, real* fitnesses, const SIZE_TYPE particlesCount) const = 0;
};

class FunctionRsj : public Function
{
private:
    SIZE_TYPE m_DimensionsCount;
    SIZE_TYPE m_PointsCount;
    real* m_Y;
    real* m_X;
public:
    __device__ FunctionRsj(const SIZE_TYPE dimensionsCount, const SIZE_TYPE pointsCount, real* configFileData)
        : m_DimensionsCount(dimensionsCount),
            m_PointsCount(pointsCount),
            m_Y(configFileData),
            m_X(configFileData + pointsCount) {}

    __device__ ~FunctionRsj()
    {
        // m_Y points to the beginning of the config
        // file data, use it for destruction as this 
        // object took ownership of configFilDeata.
        delete[] m_Y;
    }

    __device__ void Evaluate(const real* __restrict__ positions, real* fitnesses, const SIZE_TYPE particlesCount) const
    {
        // Implement evaluation of FunctionRsj here.
    }
};

__global__ void evaluate_fitnesses(
    const real* __restrict__ positions,
    real* fitnesses,
    Function const* const* __restrict__ function,
    const SIZE_TYPE particlesCount)
{
    // This whole kernel is just a proxy as kernels
    // cannot be member functions.
    (*function)->Evaluate(positions, fitnesses, particlesCount);
}

__global__ void create_function(
    Function** function,
    SIZE_TYPE dimensionsCount,
    SIZE_TYPE pointsCount,
    real* configFileData)
{
    // It is necessary to create object representing a function
    // directly in global memory of the GPU device for virtual
    // functions to work correctly, i.e. virtual function table
    // HAS to be on GPU as well.
    if (threadIdx.x == 0 && blockIdx.x == 0)
    {
        (*function) = new FunctionRsj(dimensionsCount, pointsCount, configFileData);
    }
}

__global__ void delete_function(Function** function)
{
    delete *function;
}

int main()
{
    // Lets just assume d_FunctionConfigData, d_Positions,
    // d_Fitnesses are arrays allocated on GPU already ...

    // Create function.
    Function** d_Function;
    cudaMalloc(&d_Function, sizeof(Function**));
    create_function<<<1, 1>>>(d_Function, 10, 10, d_FunctionConfigData);

    // Evaluate using proxy kernel.
    evaluate_fitnesses<<<
        m_Configuration.GetEvaluationGridSize(),
        m_Configuration.GetEvaluationBlockSize(),
        m_Configuration.GetEvaluationSharedMemorySize()>>>(
        d_Positions,
        d_Fitnesses,
        d_Function,
        m_Configuration.GetParticlesCount());

    // Delete function object on GPU.
    delete_function<<<1, 1>>>(d_Function);
}
类函数
{
公众:
__设备函数(){}
__设备{virtual~函数(){}
__设备虚拟空隙评估(常数实*常数限制\位置、真实*适合度、常数大小\类型粒子数)常数=0;
};
类函数sj:公共函数
{
私人:
尺寸、类型、尺寸和尺寸;
尺寸/类型m\U点孔型;
真的吗;
真实*m_X;
公众:
__设备\uuuuuu函数rSj(常量大小\u类型维度NT、常量大小\u类型点斯科特、实*配置文件数据)
:m_dimensionscont(dimensionscont),
m_PointScont(PointScont),
m_Y(配置文件数据),
m_X(configFileData+PointScont){}
__设备\函数sj()
{
//m_Y指向配置的开头
//文件数据,使用它进行销毁,如下所示
//对象取得了configFilDeata的所有权。
删除[]m_Y;
}
__设备无效评估(常数实值*\uuuu限制\uuuuuu位置、实值*适合度、常数大小\u类型粒子数)常数
{
//在此处执行函数Rsj的评估。
}
};
__全局无效评估适用性(
常量实*限制位置,
真正的健康,
函数常数*常数*限制函数,
常量大小(类型粒子数)
{
//整个内核只是内核的代理
//不能是成员函数。
(*功能)->评估(位置、适合度、粒子数);
}
__全局\无效创建\函数(
功能**功能,
尺寸\u类型尺寸,
尺寸\u类型指针,
real*configFileData)
{
//有必要创建表示函数的对象
//直接在GPU设备的全局内存中进行虚拟存储
//功能正常工作,即虚拟功能表
//也必须在GPU上。
if(threadIdx.x==0&&blockIdx.x==0)
{
(*函数)=新函数rSj(DimensionScont、PointScont、configFileData);
}
}
__全局\无效删除\函数(函数**函数)
{
删除*功能;
}
int main()
{
//假设d_函数配置数据,d_位置,
//d_Fitness是GPU上已分配的阵列。。。
//创建函数。
函数**d_函数;
cudaMalloc(&d_函数,sizeof(函数**));
创建_函数(d_函数、10、10、d_函数配置数据);
//使用代理内核进行计算。
评估适合性>(
d_位置,
d_Fitnesses,
d_函数,
m_Configuration.GetParticlesCount());
//删除GPU上的函数对象。
删除_函数(d_函数);
}

您可以在CUDA内核函数中使用多态性。这些对象只需在设备上创建即可。这通常不会很难做到,即使您需要使用来自主机的数据初始化这些对象。我提供了一个答案,用推力演示了这个概念,但当然它也可以在普通CUDA代码中工作。@Robert Crovella似乎这个问题的根源是虚拟函数表的地址特定于设备。在对象在设备之间移动的多gpu应用程序中,这会产生什么影响?例如,我在设备0上实例化一个多态类,然后将实例memcpy到设备1(其中也有相同类的实例)。该对象会破坏memcopied对象,还是会无缝地使用设备1的虚拟函数表?我不希望它工作。虚拟函数表基本上是一组指针。这些指针(地址)只适用于它们要调用的设备。事实上,我希望UVA能保证它不会起作用。你也许可以让它在非UVA环境下工作,但我不会指望它。不过,我只是在这里猜测。我自己没试过。这正是我想要的。非常感谢。还有一个后续问题:在内核或设备函数中调用
new
malloc
是否会对性能造成巨大影响?@a很好,在我的情况下,我没有经历过任何重大的开销,总之,我无法想象更好的方法来解决我的问题,所以即使
malloc
new
也会对性能造成伤害表现,我不会太在意。我比较了没有抽象类的简单方法,在CPU上创建函数,然后使用
cudaMemcpy
,但性能几乎相同。我想只有在必要时才能实施解决方案并进行优化。