2012-05-10 20 views
19

Aşağıdaki kodun (vektörlerin toplamı) örneğin sürümünü geliştirmek için iki aygıtı nasıl kullanabilirim? Daha fazla cihazı "aynı anda" kullanmak mümkün mü? Evetse, vektörlerin farklı cihazların global hafızasındaki tahsislerini nasıl yönetebilirim?çok GPU temel kullanımı

#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; 
} 

Şimdiden teşekkür ederiz. Michele

cevap

32

CUDA 4.0 piyasaya sürüldüğünden beri, sorduğunuz türde çoklu GPU hesaplamaları nispeten kolaydır. Bundan önce, aynı ana bilgisayar uygulamasındaki mutliple GPU'ları kullanmak için GPU başına bir ana iş parçacığı ve bir çeşit ileti-arası iletişim sistemi olan çok iş parçacıklı bir ana bilgisayar uygulaması kullanmanız gerekir.

Şimdi sıra ev sahibi kod bellek ayırma bölümü için böyle bir şey yapmak mümkündür:

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

(uyarı: tarayıcıda yazılı, test asla derlenmiş kendi sorumluluğunuzdadır kullanımı asla).

Buradaki temel fikir, bir aygıtta işlem hazırlarken aygıtlar arasında seçim yapmak için cudaSetDevice kullanmanızdır. Bu yüzden, yukarıdaki kod parçasında, iki GPU'yu ve ilk [/ N/2] çiftine ilk aygıtta ve ikinci (N/2) N (2/2) 'de bellek ayırdım.

// 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); 
} 

:

cihaza ana bilgisayardan veri aktarımı

kadar basit olabilir (reddi: tarayıcıda yazılı, test asla derlenmiş asla kullanımı kendi sorumluluğunuzdadır).

sonra şuna benzer olabilir kodunuzun bölümüne başlatılması çekirdek:

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]); 
    } 
} 

(reddi: tarayıcıda yazılı, test kullanımı kendi sorumluluğunuzdadır asla derlenmiş hiç).

Çekirdek çağrınıza fazladan bir argüman eklediğimi unutmayın, çünkü çekirdeğin her örneği işlemek için farklı sayıda dizi öğesiyle çağrılabilir. Gerekli değişiklikleri yapmak için size bırakacağım. Ancak, yine, temel fikir aynıdır: belirli bir GPU seçmek için cudaSetDevice kullanın, daha sonra her bir çekirdek kendi benzersiz argümanlarını alarak, normal şekilde kerneller çalıştırın.

Basit bir çoklu GPU uygulaması oluşturmak için bu parçaları birleştirebilmelisiniz. Son CUDA sürümlerinde ve birden fazla GPU uygulamasına yardımcı olmak için kullanılabilecek pek çok başka özellik vardır (birleştirilmiş adresleme, eşler arası özellikler daha fazladır), ancak başlamanız için bu yeterli olmalıdır. CUDA SDK'da daha fazla fikir için bakabileceğiniz basit bir muLti-GPU uygulaması da var.

+1

Çok çok fazla taksonomi var! Önerileriniz beni iyi başlatacak ... kötü ingilizcem için özür dilerim – micheletuttafesta

+4

Özür dilemem gereken bir şey yok, sorunun ne olduğunu anladım ve İngilizce yazdım. – talonmies

+2

Eşzamanlı yürütme elde etmek için "cudaMemcpyAsync" kullanılması tavsiye edilebilir, bkz. [CUDA çoklu GPU yürütme işlemlerinde eşzamanlılık] (http://stackoverflow.com/questions/11673154/multiple-gpus-on-cuda-concurrency-issue/35010019# 35.010.019). – JackOLantern