podstawowe użycie wielu GPU
Jak mogę używać dwóch urządzeń w celu ulepszenia np. wykonanie poniższego kodu (suma wektorów)? Czy możliwe jest używanie większej ilości urządzeń "w tym samym czasie"? Jeśli tak, jak mogę zarządzać przydziałami wektorów w pamięci globalnej różnych urządzeń?
#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;
}
Z góry dziękuję.
Michele 1 answers
Odkąd CUDA 4.0 została wydana, obliczenia wielordzeniowe typu, O który pytasz, są stosunkowo łatwe. Wcześniej trzeba było użyć wielowątkowej aplikacji hosta z jednym wątkiem hosta na GPU i pewnego rodzaju systemu komunikacji między wątkami, aby korzystać z mutliple GPU wewnątrz tej samej aplikacji hosta.
Teraz można zrobić coś takiego dla części alokacji pamięci w kodzie Hosta:
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) );
}
(zastrzeżenie: napisane w przeglądarce, nigdy skompilowany, nigdy nie testowany, stosować na własne ryzyko).
Podstawową ideą jest to, że używasz cudaSetDevice
do wyboru między urządzeniami podczas preformowania operacji na urządzeniu. Tak więc w powyższym fragmencie założyłem dwa GPU i przydzieloną pamięć na każdym [(N/2) podwaja się na pierwszym urządzeniu i N-(N/2) na drugim].
Transfer danych z hosta do urządzenia może być tak prosty, jak:
// 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);
}
(zastrzeżenie: napisane w przeglądarce, nigdy nie skompilowane, nigdy nie Przetestowane, użyj we własnym zakresie ryzyko).
Sekcja uruchamiająca jądro Twojego kodu może wyglądać następująco:
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] );
}
}
(zastrzeżenie: napisane w przeglądarce, nigdy nie skompilowane, nigdy nie Przetestowane, używać na własne ryzyko).
Zauważ, że dodałem dodatkowy argument do twojego wywołania jądra, ponieważ każda instancja jądra może być wywołana z inną liczbą elementów tablicy do przetworzenia. Pozostawiam Ci opracowanie wymaganych modyfikacji.
Ale, znowu, podstawowa idea jest taka sama: użyj cudaSetDevice
, aby wybrać biorąc pod uwagę GPU, uruchamiamy na nim jądra w normalny sposób, z każdym jądrem otrzymującym własne unikalne argumenty.
Powinieneś być w stanie połączyć te części, aby stworzyć prostą aplikację Multi-GPU. Istnieje wiele innych funkcji, które mogą być używane w najnowszych wersjach CUDA i sprzęcie, aby pomóc wielu aplikacjom GPU(jak zunifikowane adresowanie, udogodnienia peer-to-peer są więcej), ale to powinno wystarczyć, aby zacząć. Istnieje również prosta aplikacja muLti-GPU w CUDA SDK można spojrzeć na więcej pomysłów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-10 09:48:40