2012-05-10 42 views
19

Làm cách nào để tôi có thể sử dụng hai thiết bị để cải thiện ví dụ hiệu suất của mã sau (tổng số vectơ)? Có thể sử dụng nhiều thiết bị hơn "cùng một lúc" không? Nếu có, làm cách nào tôi có thể quản lý việc phân bổ vectơ trên bộ nhớ chung của các thiết bị khác nhau?sử dụng cơ bản nhiều 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; 
} 

Cảm ơn bạn trước. Michele

Trả lời

32

Kể từ khi CUDA 4.0 được phát hành, tính toán đa GPU của loại bạn đang hỏi là tương đối dễ dàng. Trước đó, bạn sẽ cần phải sử dụng một ứng dụng máy chủ đa luồng với một luồng chủ trên mỗi GPU và một số loại hệ thống liên lạc liên ren để sử dụng các GPU trong cùng một ứng dụng máy chủ.

Bây giờ chúng ta có thể làm điều gì đó như thế này cho các phần phân bổ bộ nhớ mã máy chủ của bạn:

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

(từ chối trách nhiệm: bằng văn bản trong trình duyệt, không bao giờ được biên dịch, không bao giờ được thử nghiệm, sử dụng tự chịu rủi ro).

Ý tưởng cơ bản ở đây là bạn sử dụng cudaSetDevice để chọn giữa các thiết bị khi bạn đang hoạt động định dạng trước trên thiết bị. Vì vậy, trong đoạn mã trên, tôi đã giả định hai GPU và bộ nhớ phân bổ trên mỗi [(N/2) tăng gấp đôi trên thiết bị đầu tiên và N- (N/2) vào thứ hai].

Việc chuyển dữ liệu từ máy chủ để thiết bị có thể đơn giản như:

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

(từ chối trách nhiệm: bằng văn bản trong trình duyệt, không bao giờ được biên dịch, không bao giờ được thử nghiệm, sử dụng tự chịu rủi ro).

Kernel phần của mã của bạn tung ra sau đó có thể giống như thế:

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

(từ chối trách nhiệm: bằng văn bản trong trình duyệt, không bao giờ được biên dịch, không bao giờ được thử nghiệm, sử dụng tự chịu rủi ro).

Lưu ý rằng tôi đã thêm một đối số bổ sung vào cuộc gọi hạt nhân của bạn, bởi vì mỗi cá thể của hạt nhân có thể được gọi với một số phần tử mảng khác nhau để xử lý. Tôi sẽ để lại cho bạn để làm việc ra các sửa đổi cần thiết. Nhưng, một lần nữa, ý tưởng cơ bản là giống nhau: sử dụng cudaSetDevice để chọn một GPU nhất định, sau đó chạy hạt nhân theo cách thông thường, với mỗi hạt nhân nhận được các đối số duy nhất của riêng nó.

Bạn sẽ có thể đặt các bộ phận này lại với nhau để tạo ra một ứng dụng đa GPU đơn giản. Có rất nhiều tính năng khác có thể được sử dụng trong các phiên bản và phần cứng CUDA gần đây để hỗ trợ nhiều ứng dụng GPU (như địa chỉ hợp nhất, cơ sở ngang hàng), nhưng điều này là đủ để bạn bắt đầu. Ngoài ra còn có một ứng dụng muLti-GPU đơn giản trong SDK CUDA mà bạn có thể xem xét để có thêm ý tưởng.

+1

Cảm ơn bạn rất nhiều tài năng !! Đề xuất của bạn sẽ giúp tôi bắt đầu tốt ... xin lỗi vì tiếng anh xấu của tôi – micheletuttafesta

+4

Không có gì để xin lỗi, tôi hiểu câu hỏi và tiếng Anh được viết hoàn hảo. – talonmies

+2

Sử dụng 'cudaMemcpyAsync' sẽ được khuyến khích để đạt được thực hiện đồng thời, xem [Đồng thời trong các lệnh thực thi đa GPU CUDA] (http://stackoverflow.com/questions/11673154/multiple-gpus-on-cuda-concurrency-issue/35010019# 35010019). – JackOLantern

Các vấn đề liên quan