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