2012-05-10 63 views
19

如何使用兩個裝置,以改善例如 以下代碼(矢量的總和)的表現? 「同時」可以使用更多設備嗎? 如果是,我如何管理不同設備的全局內存上的向量分配?多GPU的基本用法

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <time.h> 
#include <cuda.h> 

#define NB 32 
#define NT 500 
#define N NB*NT 

__global__ void add(double *a, double *b, double *c); 

//=========================================== 
__global__ void add(double *a, double *b, double *c){ 

    int tid = threadIdx.x + blockIdx.x * blockDim.x; 

    while(tid < N){ 
     c[tid] = a[tid] + b[tid]; 
     tid += blockDim.x * gridDim.x; 
    } 

} 

//============================================ 
//BEGIN 
//=========================================== 
int main(void) { 

    double *a, *b, *c; 
    double *dev_a, *dev_b, *dev_c; 

    // allocate the memory on the CPU 
    a=(double *)malloc(N*sizeof(double)); 
    b=(double *)malloc(N*sizeof(double)); 
    c=(double *)malloc(N*sizeof(double)); 

    // allocate the memory on the GPU 
    cudaMalloc((void**)&dev_a, N * sizeof(double)); 
    cudaMalloc((void**)&dev_b, N * sizeof(double)); 
    cudaMalloc((void**)&dev_c, N * sizeof(double)); 

    // fill the arrays 'a' and 'b' on the CPU 
    for (int i=0; i<N; i++) { 
     a[i] = (double)i; 
     b[i] = (double)i*2; 
    } 

    // copy the arrays 'a' and 'b' to the GPU 
    cudaMemcpy(dev_a, a, N * sizeof(double), cudaMemcpyHostToDevice); 
    cudaMemcpy(dev_b, b, N * sizeof(double), cudaMemcpyHostToDevice); 

    for(int i=0;i<10000;++i) 
     add<<<NB,NT>>>(dev_a, dev_b, dev_c); 

    // copy the array 'c' back from the GPU to the CPU 
    cudaMemcpy(c, dev_c, N * sizeof(double), cudaMemcpyDeviceToHost); 

    // display the results 
    // for (int i=0; i<N; i++) { 
    //  printf("%g + %g = %g\n", a[i], b[i], c[i]); 
    // } 
    printf("\nGPU done\n"); 

    // free the memory allocated on the GPU 
    cudaFree(dev_a); 
    cudaFree(dev_b); 
    cudaFree(dev_c); 
    // free the memory allocated on the CPU 
    free(a); 
    free(b); 
    free(c); 

    return 0; 
} 

在此先感謝您。 米歇爾

回答

32

由於CUDA 4.0發佈了,你是想詢問類型的多GPU計算是比較容易的。在此之前,您需要使用多線程主機應用程序,每個GPU使用一個主機線程,並使用某種線程間通信系統,以便在同一主機應用程序內使用多個GPU。

現在可以爲您的主機代碼的內存分配部分做這樣的事情:

double *dev_a[2], *dev_b[2], *dev_c[2]; 
const int Ns[2] = {N/2, N-(N/2)}; 

// allocate the memory on the GPUs 
for(int dev=0; dev<2; dev++) { 
    cudaSetDevice(dev); 
    cudaMalloc((void**)&dev_a[dev], Ns[dev] * sizeof(double)); 
    cudaMalloc((void**)&dev_b[dev], Ns[dev] * sizeof(double)); 
    cudaMalloc((void**)&dev_c[dev], Ns[dev] * sizeof(double)); 
} 

(免責聲明:寫在瀏覽器中,從來沒有編制,沒有測試,風險自擔使用)。

這裏的基本想法是,你使用cudaSetDevice設備之間進行選擇,當你的設備上預成型操作。所以在上面的代碼片段中,我假設每個[(N/2)在第一個設備上是雙倍的,而在第二個設備上是N-(N/2)]上分配了兩個GPU。

數據從主機到設備的傳輸可以是簡單的:

// copy the arrays 'a' and 'b' to the GPUs 
for(int dev=0,pos=0; dev<2; pos+=Ns[dev], dev++) { 
    cudaSetDevice(dev); 
    cudaMemcpy(dev_a[dev], a+pos, Ns[dev] * sizeof(double), cudaMemcpyHostToDevice); 
    cudaMemcpy(dev_b[dev], b+pos, Ns[dev] * sizeof(double), cudaMemcpyHostToDevice); 
} 

(免責聲明:寫在瀏覽器中,從來沒有編制,沒有測試,風險自擔使用)。

內核啓動代碼的部分則可能類似於:

for(int i=0;i<10000;++i) { 
    for(int dev=0; dev<2; dev++) { 
     cudaSetDevice(dev); 
     add<<<NB,NT>>>(dev_a[dev], dev_b[dev], dev_c[dev], Ns[dev]); 
    } 
} 

(免責聲明:寫在瀏覽器中,從來沒有編制,沒有測試,風險自擔使用)。

注意,我增加了一個額外的參數,以你的內核調用,因爲內核的每個實例可以有不同數量的數組元素來處理的調用。我將給你留下來解決所需的修改。 但是,基本思想是一樣的:使用cudaSetDevice來選擇給定的GPU,然後以正常方式運行內核,每個內核都有自己獨特的參數。

你應該能夠把這些部分組合在一起,產生一個簡單的多GPU的應用程序。在最近的CUDA版本和硬件中可以使用很多其他功能來輔助多GPU應用程序(如統一尋址,點對點設施更多),但這應該足以讓您開始使用。 CUDA SDK中還有一個簡單的muLti-GPU應用程序,您可以查看更多的想法。

+1

非常感謝你talonmies!你的建議會讓我開始好...對不起我的英文不好。 – micheletuttafesta

+4

沒有什麼可道歉的,我理解這個問題和英文寫得完美。 – talonmies

+2

使用'cudaMemcpyAsync'將是可取的,以實現併發執行,參見[併發CUDA多GPU執行(http://stackoverflow.com/questions/11673154/multiple-gpus-on-cuda-concurrency-issue/35010019# 35010019)。 – JackOLantern