2015-05-04 6 views
9

सीयूडीए कोड के कार्यान्वयन के दौरान मुझे अक्सर कुछ उपयोगिता कार्यों की आवश्यकता होती है, जिन्हें डिवाइस से और होस्ट कोड से भी कहा जाएगा। तो मैं इन कार्यों को __host__ __device__ के रूप में घोषित करता हूं। यह ठीक है और संभव डिवाइस/मेजबान अक्षमता #ifdef CUDA_ARCH द्वारा संभाला जा सकता है।टेम्पलेट __host__ __device__ कॉलिंग होस्ट परिभाषित फ़ंक्शंस

समस्याएं तब आती हैं जब उपयोगिता फ़ंक्शन टेम्पलेट होता है यानी। कुछ मज़ेदार प्रकार से। - एक बार डिवाइस के लिए और एक बार भिन्न नाम के साथ मेजबान कोड के लिए (मैं __host__ __device__ पर ओवरलोड नहीं कर सकते

calling a __host__ function from a __host__ __device__ function is not allowed 
     detected during instantiation of "int foo(const T &) [with T=HostObject]" 

केवल समाधान मैं जानता हूँ कि समारोह में दो बार परिभाषित करने के लिए है: टेम्पलेट उदाहरण एक __host__ फ़ंक्शन को कॉल यदि मैं यह चेतावनी मिलती है)। लेकिन इसका मतलब है कि कोड डुप्लिकेशन और अन्य सभी __host__ __device__ फ़ंक्शंस हैं जो इसे कॉल करेंगे, इसे दो बार परिभाषित किया जाना चाहिए (यहां तक ​​कि अधिक कोड डुप्लिकेशन)।

सरलीकृत उदाहरण:

#include <cuda.h> 
#include <iostream> 

struct HostObject { 
    __host__ 
    int value() const { return 42; } 
}; 

struct DeviceObject { 
    __device__ 
    int value() const { return 3; } 
}; 

template <typename T> 
__host__ __device__ 
int foo(const T &obj) { 
    return obj.value(); 
} 

/* 
template <typename T> 
__host__ 
int foo_host(const T &obj) { 
    return obj.value(); 
} 

template <typename T> 
__device__ 
int foo_device(const T &obj) { 
    return obj.value(); 
} 
*/ 

__global__ void kernel(int *data) { 
    data[threadIdx.x] = foo(DeviceObject()); 
} 

int main() { 
    foo(HostObject()); 

    int *data; 
    cudaMalloc((void**)&data, sizeof(int) * 64); 
    kernel<<<1, 64>>>(data); 
    cudaThreadSynchronize(); 
    cudaFree(data); 
} 

चेतावनी main() समारोह अंदर foo(HostObject()); कॉल के कारण होता है।

foo_host<> और foo_device<> समस्याग्रस्त foo<> के लिए संभावित प्रतिस्थापन हैं।

क्या कोई बेहतर समाधान है? क्या मैं डिवाइस पक्ष पर foo() के इंस्टॉलेशन को रोक सकता हूं?

+0

'foo() 'के अंदर कोई कन्स्ट्रक्टर नहीं कहा जाता है। समस्या वास्तव में चेतावनी कहती है। मैं पूछ रहा हूं कि क्या मैं जेनेरिक फ़ंक्शन को दो बार परिभाषित किए बिना इसे किसी भी तरह ठीक कर सकता हूं। – Johny

+0

चेतावनी मुख्य कार्य में 'foo (HostObject()) 'के कारण होती है। रचनाकारों के साथ कोई समस्या नहीं है क्योंकि जब तक कि मैं खुद से एक घोषित नहीं करता तब तक स्वचालित रूप से जेनरेट किए गए कन्स्ट्रक्टर (मेजबान और डिवाइस कंपेलरों दोनों द्वारा) होगा। – Johny

+0

क्षमा करें, अब मैं आपका पॉइंट देखता हूं - यह देखने में इतना आसान नहीं है कि संकलक के बिना त्रुटि कहां दिखायी जाती है। इसलिए मुझे विश्वास है कि आपके प्रश्न में इसका उल्लेख करना उपयोगी होगा। –

उत्तर

5

आप __host__ __device__ फ़ंक्शन टेम्पलेट इंस्टेंटेशन के आधा के तत्कालता को रोक नहीं सकते हैं। यदि आप होस्ट (डिवाइस) पर कॉल करके फ़ंक्शन को तुरंत चालू करते हैं, तो संकलक डिवाइस (होस्ट) आधे को भी चालू करेगा।

CUDA 7.0 के रूप में आपके उपयोग के मामले के लिए सबसे अच्छा आप निम्नलिखित उदाहरण में #pragma hd_warning_disable का उपयोग करके चेतावनी को दबाना है और यह सुनिश्चित करना है कि फ़ंक्शन गलत तरीके से नहीं कहा जाता है।

#include <iostream> 
#include <cstdio> 

#pragma hd_warning_disable 
template<class Function> 
__host__ __device__ 
void invoke(Function f) 
{ 
    f(); 
} 

struct host_only 
{ 
    __host__ 
    void operator()() 
    { 
    std::cout << "host_only()" << std::endl; 
    } 
}; 

struct device_only 
{ 
    __device__ 
    void operator()() 
    { 
    printf("device_only(): thread %d\n", threadIdx.x); 
    } 
}; 

__global__ 
void kernel() 
{ 
    // use from device with device functor 
    invoke(device_only()); 

    // XXX error 
    // invoke(host_only()); 
} 

int main() 
{ 
    // use from host with host functor 
    invoke(host_only()); 

    kernel<<<1,1>>>(); 
    cudaDeviceSynchronize(); 

    // XXX error 
    // invoke(device_only()); 

    return 0; 
} 
संबंधित मुद्दे