2012-12-30 3 views
5

CUDA सी श्रेष्ठ व्यवहार मार्गदर्शिका संस्करण 5.0, धारा 6.1.2 में, यह लिखा है कि:असीमित स्मृति प्रतिलिपि के लिए पेज-सक्षम मेमोरी का उपयोग करने का प्रभाव?

cudaMemcpy(), अतुल्यकालिक अंतरण संस्करण पिन किए गए मेजबान स्मृति (पिन की गई मेमोरी देखें) की आवश्यकता है, और के साथ इसके विपरीत इसमें अतिरिक्त तर्क, एक स्ट्रीम आईडी शामिल है।

इसका मतलब है कि यदि मैं सरल स्मृति का उपयोग करता हूं तो cudaMemcpyAsync फ़ंक्शन विफल होना चाहिए।

लेकिन ऐसा नहीं हुआ।

कर्नेल::

__global__ void kernel_increment(float* src, float* dst, int n) 
{ 
    int tid = blockIdx.x * blockDim.x + threadIdx.x; 

    if(tid<n) 
     dst[tid] = src[tid] + 1.0f; 
} 

मुख्य:

int main() 
{ 
    float *hPtr1, *hPtr2, *dPtr1, *dPtr2; 

    const int n = 1000; 

    size_t bytes = n * sizeof(float); 

    cudaStream_t str1, str2; 

    hPtr1 = new float[n]; 
    hPtr2 = new float[n]; 

    for(int i=0; i<n; i++) 
     hPtr1[i] = static_cast<float>(i); 

    cudaMalloc<float>(&dPtr1,bytes); 
    cudaMalloc<float>(&dPtr2,bytes); 

    dim3 block(16); 
    dim3 grid((n + block.x - 1)/block.x); 

    cudaStreamCreate(&str1); 
    cudaStreamCreate(&str2); 

    cudaMemcpyAsync(dPtr1,hPtr1,bytes,cudaMemcpyHostToDevice,str1); 
    kernel_increment<<<grid,block,0,str2>>>(dPtr1,dPtr2,n); 
    cudaMemcpyAsync(hPtr2,dPtr2,bytes,cudaMemcpyDeviceToHost,str1); 

    printf("Status: %s\n",cudaGetErrorString(cudaGetLastError())); 

    cudaDeviceSynchronize(); 

    printf("Status: %s\n",cudaGetErrorString(cudaGetLastError())); 

    cudaStreamDestroy(str1); 
    cudaStreamDestroy(str2); 

    cudaFree(dPtr1); 
    cudaFree(dPtr2); 

    for(int i=0; i<n; i++) 
     std::cout<<hPtr2[i]<<std::endl; 

    delete[] hPtr1; 
    delete[] hPtr2; 

    return 0; 
} 

कार्यक्रम सही उत्पादन दिया

बस परीक्षण के लिए, मैं निम्नलिखित कार्यक्रम की कोशिश की। सरणी सफलतापूर्वक बढ़ी।

cudaMemcpyAsync पृष्ठ लॉक किए गए मेमोरी के बिना निष्पादित कैसे किया गया? क्या मुझे यहां कुछ याद आ रही है?

+0

@ नोल्वेनलेगेन ... वास्तव में शुरुआत से ही इसकी आवश्यकता है। मैंने इसे पिछले सीयूडीए गाइड में भी पढ़ा है। – sgarizvi

+2

@ नोलवेनलेगुएन: यह बिल्कुल अपेक्षित व्यवहार है, कोई "ब्लैक-बॉक्स सामान" शामिल नहीं है। यदि आपके पास चर्चा में जोड़ने के लिए कुछ भी रचनात्मक नहीं है, तो कृपया इसमें शामिल न होने के लिए स्वतंत्र महसूस करें। – talonmies

+3

फ़ंक्शन के लिए प्रलेखन _This फ़ंक्शन अधिकांश उपयोग मामलों के लिए एसिंक्रोनस व्यवहार प्रदर्शित करता है ._।यदि पेजेबल मेमोरी का उपयोग किया जाता है तो ड्राइवर को स्मृति को एक गैर-पेजेबल बफर में कॉपी करना होगा। यदि स्थानांतरण आकार ड्राइवर के गैर-पेजेबल बफर से अधिक है तो ड्राइवर शेष हस्तांतरण को पूरा करने के लिए गैर-पेजेबल बफर के लिए उपलब्ध होने की प्रतीक्षा करता है। –

उत्तर

9

cudaMemcpyAsync मूल रूप से cudaMemcpy का एक असीमित संस्करण है। इसका मतलब है कि कॉपी कॉल जारी होने पर यह कॉलिंग होस्ट थ्रेड को अवरुद्ध नहीं करता है। यह कॉल का मूल व्यवहार है।

वैकल्पिक रूप से, अगर कॉल गैर डिफ़ॉल्ट धारा में शुरू की है, और अगर मेजबान स्मृति पिन किए गए आवंटन है, और डिवाइस एक नि: शुल्क डीएमए प्रतिलिपि इंजन है, कॉपी आपरेशन भी हो सकता है, जबकि GPU एक साथ एक और प्रदर्शन ऑपरेशन: या तो कर्नेल निष्पादन या दूसरी प्रतिलिपि (दो डीएमए प्रतिलिपि इंजनों के साथ जीपीयू के मामले में)। यदि ये सभी शर्तें संतुष्ट नहीं हैं, तो GPU पर ऑपरेशन मानक cudaMemcpy कॉल, यानी कार्यात्मक रूप से समान है। यह GPU पर संचालन संचालन करता है, और कोई एक साथ कॉपी-कर्नेल निष्पादन या एक साथ कई प्रतियां नहीं हो सकती हैं। केवल अंतर यह है कि ऑपरेशन कॉलिंग होस्ट थ्रेड को अवरुद्ध नहीं करता है।

आपके उदाहरण कोड में, होस्ट स्रोत और गंतव्य मेमोरी पिन नहीं होती है। इसलिए स्मृति हस्तांतरण कर्नेल निष्पादन (यानी वे GPU पर क्रमबद्ध संचालन) के साथ ओवरलैप नहीं कर सकते हैं। कॉल अभी भी होस्ट पर असीमित हैं। तो तुम क्या है कार्यात्मक के बराबर है:

cudaMemcpy(dPtr1,hPtr1,bytes,cudaMemcpyHostToDevice); 
kernel_increment<<<grid,block>>>(dPtr1,dPtr2,n); 
cudaMemcpy(hPtr2,dPtr2,bytes,cudaMemcpyDeviceToHost); 
अपवाद है कि सभी कॉल मेजबान पर अतुल्यकालिक हैं साथ

, तो cudaDeviceSynchronize() कॉल पर बजाय स्मृति हस्तांतरण कॉल में से प्रत्येक में मेजबान धागा ब्लॉक।

यह बिल्कुल अपेक्षित व्यवहार है।

+0

okkk ... इसका मतलब स्मृति प्रतिलिपि और कर्नेल निष्पादन के बीच ओवरलैपिंग प्राप्त करना है, मुझे पेज लॉक मेमोरी का उपयोग करना होगा। अन्यथा परिणाम सही होगा लेकिन ओवरलैपिंग नहीं होगी। सही? – sgarizvi

+0

@ sgar91: हाँ, यह इस तरह काम करता है। – talonmies

+0

क्या होता है यदि उन सभी स्थितियों * संतुष्ट हैं? क्या कर्नेल गलत परिणाम देगा क्योंकि सभी मेमोरी को डिवाइस पर कॉपी नहीं किया गया है? –

संबंधित मुद्दे