2014-11-08 5 views
1

CUDA는 가상 함수가있는 클래스가 커널 함수로 전달되는 것을 허용하지 않습니다. 이 제한 사항에 대한 해결 방법이 있습니까?장치 측 CUDA 가상 함수를 구현하는 방법은 무엇입니까?

커널 기능 내에서 다형성을 사용하고 싶습니다.

감사합니다.

+2

당신은 내 다형성을 사용할 수 있습니다 : 그것은 희망 아이디어를 얻을하는 데 도움이됩니다 ... 이것은 내가 내 상황에서 다형성을 달성하는 방법을 내 코드의 단순화 된 버전입니다,하지만 난 그게 더 할 수없는 말을하고 있지 않다 CUDA 커널 기능. 객체는 단순히 장치에서 만들어야합니다. 호스트에서 가져온 데이터로 객체를 초기화해야하는 경우에도 일반적으로 그렇게하기가 어렵지 않습니다. 나는 응답 [여기] (http://stackoverflow.com/questions/22988244/polymorphism-and-derived-classes-in-cuda-cuda-thrust/23476510?s=2|1.7036#23476510)을 보여 주며 개념을 보여줍니다. 추력으로, 물론 일반 CUDA 코드에서도 작동하도록 만들 수 있습니다. –

+0

@Robert Crovella이 문제의 원인은 장치에 고유 한 가상 함수 테이블의 주소입니다. 객체가 장치간에 이동하는 다중 gpu 응용 프로그램에 어떤 영향이 있습니까? 전의. 장치 0에 다형성 클래스를 인스턴스화 한 다음 장치 1에 인스턴스를 memcpy (동일한 클래스의 인스턴스가있는 경우)합니다. 그 객체가 memcopied 객체를 깨뜨릴 것입니까, 아니면 디바이스 1의 가상 함수 테이블을 완벽하게 사용합니까? – Acerebral

+0

나는 그것을 기대하지 않을 것이다. 가상 함수 표는 기본적으로 포인터 집합입니다. 이러한 포인터 (주소)는 호출하려는 장치에 대해서만 정확할 것입니다. 사실 UVA가 제대로 작동하지 않을 것이라고 보장 할 수있을 것으로 기대합니다. 비 UVA 설정에서 작동하도록 할 수는 있지만 그다지 믿을 수는 없습니다. 그러나 나는 단지 여기에서 추측하고있다. 나는 그것을 직접 시도하지 않았다. –

답변

3

로버트 Crovella의 코멘트의 가장 중요한 부분은 다음과 같습니다

객체는 단순히 디바이스에 생성 될 필요가있다.

그런 점을 염두에 두면서, 나는 추상적 인 class Function을 가진 상황을 다루었으며, 그 다음에 다른 기능과 평가를 캡슐화 한 일부 구현을 다루었습니다.

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); 
} 
+0

이것은 내가 찾고있는 것입니다. 고맙습니다!! 하나의 후속 질문 : 커넬이나 디바이스 함수 내에서'new' 또는'malloc'를 거대한 퍼포먼스에 부딪 히지 않는 것입니까? – Acerebral

+0

@Acerebral 잘 제 경우에는 어떤 중요한 오버 헤드를 경험하지 못했습니다. 그리고 모든 문제를 해결하는 방법을 더 잘 상상할 수 없으므로 malloc 또는 new가 성능을 해칠지라도 나는별로 신경 쓰지 않을 것입니다. 추상 클래스가없는 단순한 접근법과 비교해 보았습니다. CPU에 함수를 만들고 'cudaMemcpy'를 사용했지만 성능은 거의 같았습니다. 솔루션을 구현하고 필요한 경우에만 최적화하는 것 같습니다. –

관련 문제