2012-07-16 9 views
7

मैं क्यूडीए प्रोग्रामिंग के लिए बहुत नया हूं और एनवीडिया द्वारा प्रदान की गई 'कुडा सी प्रोग्रामिंग गाइड' पढ़ रहा था। (http://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/CUDA_C_Programming_Guide.pdf)2 वीडियो कार्ड के साथ CUDA सी प्रोग्रामिंग

पृष्ठ 25 में, इसमें निम्न सी कोड है जो मैट्रिक्स गुणा करता है। क्या आप कृपया मुझे बता सकते हैं कि मैं दो डिवाइसों पर यह कोड कैसे चला सकता हूं? (अगर मेरे कंप्यूटर में दो एनवीडा सीयूडीए सक्षम कार्ड स्थापित हैं)। क्या आप मुझे एक उदाहरण के साथ दिखा सकते हैं।

// Matrices are stored in row-major order: 
// M(row, col) = *(M.elements + row * M.stride + col) 
typedef struct { 
    int width; 
    int height; 
    int stride; 
    float* elements; 
} Matrix; 

// Get a matrix element 
__device__ float GetElement(const Matrix A, int row, int col) 
{ 
    return A.elements[row * A.stride + col]; 
} 

// Set a matrix element 
__device__ void SetElement(Matrix A, int row, int col, float value) 
{ 
    A.elements[row * A.stride + col] = value; 
} 

// Get the BLOCK_SIZExBLOCK_SIZE sub-matrix Asub of A that is 
// located col sub-matrices to the right and row sub-matrices down 
// from the upper-left corner of A 
__device__ Matrix GetSubMatrix(Matrix A, int row, int col) 
{ 
    Matrix Asub; 
    Asub.width = BLOCK_SIZE; 
    Asub.height = BLOCK_SIZE; 
    Asub.stride = A.stride; 
    Asub.elements = &A.elements[A.stride * BLOCK_SIZE * row + BLOCK_SIZE * col]; 
    return Asub; 
    } 

// Thread block size 
#define BLOCK_SIZE 16 

// Forward declaration of the matrix multiplication kernel 
__global__ void MatMulKernel(const Matrix, const Matrix, Matrix); 

// Matrix multiplication - Host code 
// Matrix dimensions are assumed to be multiples of BLOCK_SIZE 
void MatMul(const Matrix A, const Matrix B, Matrix C) 
{ 
    // Load A and B to device memory 
    Matrix d_A; 
    d_A.width = d_A.stride = A.width; d_A.height = A.height; 
    size_t size = A.width * A.height * sizeof(float); 
    cudaMalloc(&d_A.elements, size); 
    cudaMemcpy(d_A.elements, A.elements, size, cudaMemcpyHostToDevice); 
    Matrix d_B; 
    d_B.width = d_B.stride = B.width; d_B.height = B.height; 
    size = B.width * B.height * sizeof(float); 
    cudaMalloc(&d_B.elements, size); 
    cudaMemcpy(d_B.elements, B.elements, size, cudaMemcpyHostToDevice); 

    // Allocate C in device memory 
    Matrix d_C; 
    d_C.width = d_C.stride = C.width; d_C.height = C.height; 
    size = C.width * C.height * sizeof(float); 
    cudaMalloc(&d_C.elements, size); 

    // Invoke kernel 
    dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE); 
    dim3 dimGrid(B.width/dimBlock.x, A.height/dimBlock.y); 
    MatMulKernel<<<dimGrid, dimBlock>>>(d_A, d_B, d_C); 

    // Read C from device memory 
    cudaMemcpy(C.elements, d_C.elements, size, cudaMemcpyDeviceToHost); 

    // Free device memory 
    cudaFree(d_A.elements); 
    cudaFree(d_B.elements); 
    cudaFree(d_C.elements); 
} 

// Matrix multiplication kernel called by MatMul() 
__global__ void MatMulKernel(Matrix A, Matrix B, Matrix C) 
{ 
    // Block row and column 
    int blockRow = blockIdx.y; 
    int blockCol = blockIdx.x; 

    // Each thread block computes one sub-matrix Csub of C 
    Matrix Csub = GetSubMatrix(C, blockRow, blockCol); 

    // Each thread computes one element of Csub 
    // by accumulating results into Cvalue 
    float Cvalue = 0; 

    // Thread row and column within Csub 
    int row = threadIdx.y; 
    int col = threadIdx.x; 

    // Loop over all the sub-matrices of A and B that are 
    // required to compute Csub 
    // Multiply each pair of sub-matrices together 
    // and accumulate the results 
    for (int m = 0; m < (A.width/BLOCK_SIZE); ++m) 
    { 
     // Get sub-matrix Asub of A 
     Matrix Asub = GetSubMatrix(A, blockRow, m); 
     // Get sub-matrix Bsub of B 
     Matrix Bsub = GetSubMatrix(B, m, blockCol); 

     // Shared memory used to store Asub and Bsub respectively 
     __shared__ float As[BLOCK_SIZE][BLOCK_SIZE]; 
     __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE]; 

     // Load Asub and Bsub from device memory to shared memory 
     // Each thread loads one element of each sub-matrix 
     As[row][col] = GetElement(Asub, row, col); 
     Bs[row][col] = GetElement(Bsub, row, col); 

     // Synchronize to make sure the sub-matrices are loaded 
     // before starting the computation 
     __syncthreads(); 

     // Multiply Asub and Bsub together 
     for (int e = 0; e < BLOCK_SIZE; ++e) 
      Cvalue += As[row][e] * Bs[e][col]; 

     // Synchronize to make sure that the preceding 
     // computation is done before loading two new 
     // sub-matrices of A and B in the next iteration 
     __syncthreads(); 
    } 

    // Write Csub to device memory 
    // Each thread writes one element 
    SetElement(Csub, row, col, Cvalue); 
} 
+0

मुझे पता है कि एनवीआईडीआईए ने सीयूडीए 3.0 के साथ अपने एकाधिक डिवाइस एपीआई में कुछ सुधार लाए हैं। प्रत्येक बार जब सीयूडीए एक जीपीयू के साथ बातचीत करता है, तो यह एक थ्रेड के संदर्भ में करता है, यदि आप एकाधिक जीपीयू के साथ बातचीत करना चाहते हैं तो आपको कोड में दोनों मैन्युअल रूप से इसे स्वयं करना होगा, लेकिन आपको उस विशिष्ट गणितीय ऑपरेशन को मैन्युअल रूप से विघटित करना होगा, जिसे आप चाहते हैं प्रदर्शन करें (इस मामले में, मैट्रिक्स मल्टी, जो शायद कठिन नहीं है, लेकिन यह बिल्कुल मामूली सामान नहीं है, क्योंकि आपको मानचित्र/दृष्टिकोण की तरह कम करने की आवश्यकता है)। संपादित करें: यदि आप केवल वही चाहते हैं जो आप चाहते हैं तो यह आपकी सहायता करना आसान होगा। – Svend

उत्तर

6

एकाधिक GPUs पर CUDA कर्नेल चलाने के लिए कोई "स्वचालित" तरीका नहीं है।

आपको मैट्रिक्स गुणात्मक समस्या को स्वतंत्र संचालन में विघटित करने का एक तरीका तैयार करना होगा जिसे समानांतर में चलाया जा सकता है (इसलिए प्रत्येक जीपीयू पर समानांतर में)। एक साधारण उदाहरण के रूप में:

C = A.BC = [A].[B1|B2] = [A.B1|A.B2] जहां B1 और B2 उपयुक्त रूप से कर रहे हैं आकार मैट्रिक्स B और | को दर्शाता है columnwise concantenation के कॉलम युक्त मैट्रिक्स के बराबर है। आप अलग-अलग मैट्रिक्स गुणात्मक संचालन के रूप में A.B1 और A.B2 की गणना कर सकते हैं, और फिर परिणामस्वरूप पनडुब्बियों को होस्ट मेमोरी में कॉपी करते समय संगतता निष्पादित कर सकते हैं।

एक बार आपके पास उपयुक्त अपघटन योजना हो जाने के बाद, आप इसे CUDA 4.x API में मानक बहु-जीपीयू सुविधाओं का उपयोग करके कार्यान्वित करते हैं। सीयूडीए एपीआई का उपयोग करके बहु-जीपीयू प्रोग्रामिंग के एक महान अवलोकन के लिए, मैं पॉलिसी माइकिकेविचियस की जीटीसी 2012 से उत्कृष्ट बात देखने की सलाह देता हूं, जो एक स्ट्रीमिंग वीडियो और पीडीएफ here के रूप में उपलब्ध है।

+0

आपके सभी उत्तरों के लिए बहुत बहुत धन्यवाद। उन्होंने बहुत मदद की। –

2

मूल बातें CUDA C Programming Guide under section 3.2.6.

में वर्णित मूल रूप से, आप जो पर GPU अपने वर्तमान मेजबान धागा cudaSetDevice() फोन करके पर चल रही है सेट कर सकते हैं। फिर भी आपको अपने जीपीयू में विभाजित होने के लिए अपने दिनचर्या को विघटित करने के लिए अपना कोड लिखना होगा।