ultima quadro m1000m gpus geforce developer compatible card cuda gpu multi-gpu

cuda - quadro - nvidia gpu



uso básico multi-GPU (1)

Desde que se lanzó CUDA 4.0, los cálculos de múltiples GPU del tipo que está preguntando son relativamente fáciles. Antes de eso, tendría que usar una aplicación de host de subprocesos múltiples con un subproceso de host por GPU y algún tipo de sistema de comunicación entre subprocesos para usar GPU de múltiples enlaces dentro de la misma aplicación de host.

Ahora es posible hacer algo como esto para la parte de asignación de memoria de su código de host:

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

(Descargo de responsabilidad: escrito en el navegador, nunca compilado, nunca probado, usar bajo su propio riesgo).

La idea básica aquí es que utiliza cudaSetDevice para seleccionar entre dispositivos cuando realiza operaciones de preformado en un dispositivo. Así que en el fragmento de código anterior, asumí dos GPU y asigné memoria en cada [(N / 2) dobles en el primer dispositivo y N- (N / 2) en el segundo].

La transferencia de datos desde el host al dispositivo podría ser tan simple como:

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

(Descargo de responsabilidad: escrito en el navegador, nunca compilado, nunca probado, usar bajo su propio riesgo).

La sección de lanzamiento del kernel de su código podría verse algo así como:

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

(Descargo de responsabilidad: escrito en el navegador, nunca compilado, nunca probado, usar bajo su propio riesgo).

Tenga en cuenta que he agregado un argumento adicional a su llamada al kernel, ya que cada instancia del kernel puede ser invocada con un número diferente de elementos de matriz para procesar. Te lo dejo a ti para que te resuelva las modificaciones requeridas. Pero, una vez más, la idea básica es la misma: use cudaSetDevice para seleccionar una GPU determinada, luego ejecute los kernels en la forma normal, con cada kernel obteniendo sus propios argumentos únicos.

Debería poder juntar estas piezas para producir una aplicación de GPU múltiple simple. Hay muchas otras características que se pueden usar en las últimas versiones de CUDA y en el hardware para ayudar a múltiples aplicaciones de GPU (como el direccionamiento unificado, las instalaciones de igual a igual son más), pero esto debería ser suficiente para comenzar. También hay una aplicación muLti-GPU simple en el SDK de CUDA que puede consultar para obtener más ideas.

¿Cómo puedo usar dos dispositivos para mejorar, por ejemplo, el rendimiento del siguiente código (suma de vectores)? ¿Es posible usar más dispositivos "al mismo tiempo"? En caso afirmativo, ¿cómo puedo gestionar las asignaciones de los vectores en la memoria global de los diferentes dispositivos?

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

Gracias de antemano. Michele