tutorial run que programming parallel python cuda parallel-processing multiprocessing pycuda

python - run - que es cuda toolkit



Multiproceso Python con PyCUDA (2)

Tengo un problema que quiero dividir en varios dispositivos CUDA, pero sospecho que la arquitectura actual de mi sistema me está frenando;

Lo que he configurado es una clase de GPU, con funciones que realizan operaciones en la GPU (extraño que). Estas operaciones son del estilo.

for iteration in range(maxval): result[iteration]=gpuinstance.gpufunction(arguments,iteration)

Me había imaginado que habría N gpuinstances para dispositivos N, pero no sé lo suficiente sobre el multiprocesamiento para ver la forma más sencilla de aplicar esto para que cada dispositivo se asigne de forma asíncrona, y extrañamente algunos de los ejemplos que encontré dieron Demostraciones concretas de cotejo de resultados después del procesamiento.

¿Alguien me puede dar alguna sugerencia en esta área?

ACTUALIZACIÓN Gracias Kaloyan por su orientación en términos del área de multiprocesamiento; Si CUDA no fuera específicamente el punto de conflicto, te estaría marcando como respuesta. Lo siento.

Pervioso para jugar con esta implementación, la clase gpuinstance inició el dispositivo CUDA con import pycuda.autoinit Pero eso no pareció funcionar, arrojando errores de invalid context tan pronto como cada hilo (con el alcance correcto) se encontró con un comando cuda. Luego intenté la inicialización manual en el __init__ constructor de la clase con ...

pycuda.driver.init() self.mydev=pycuda.driver.Device(devid) #this is passed at instantiation of class self.ctx=self.mydev.make_context() self.ctx.push()

Mi suposición aquí es que el contexto se conserva entre la lista de instancias gpu se crea y cuando los subprocesos los usan, por lo que cada dispositivo se encuentra bastante en su propio contexto.

(También implementé un destructor para encargarme de pop/detach limpieza pop/detach )

El problema es que las excepciones de invalid context siguen apareciendo tan pronto como el hilo intenta tocar CUDA.

¿Alguna idea de gente? Y gracias por llegar hasta aquí. ¡Upvotes automáticos para personas que trabajan ''banana'' en su respuesta! :PAG


Lo que necesita es una implementación de subprocesos múltiples de la función incorporada del map . Here hay una implementación. Que, con una pequeña modificación para satisfacer sus necesidades particulares, obtendrá:

import threading def cuda_map(args_list, gpu_instances): result = [None] * len(args_list) def task_wrapper(gpu_instance, task_indices): for i in task_indices: result[i] = gpu_instance.gpufunction(args_list[i]) threads = [threading.Thread( target=task_wrapper, args=(gpu_i, list(xrange(len(args_list)))[i::len(gpu_instances)]) ) for i, gpu_i in enumerate(gpu_instances)] for t in threads: t.start() for t in threads: t.join() return result

Es más o menos lo mismo que lo que tienes arriba, con la gran diferencia de que no pasas tiempo esperando cada finalización de la función gpufunction .


Primero debes poner todos tus plátanos alineados en el lado CUDA de las cosas, y luego pensar en la mejor manera de hacerlo en Python [puta de representantes descarados, lo sé].

El modelo multi-GPU de CUDA es bastante sencillo pre 4.0: cada GPU tiene su propio contexto, y cada contexto debe ser establecido por un hilo host diferente. Así que la idea en pseudocódigo es:

  1. La aplicación se inicia, el proceso utiliza la API para determinar la cantidad de GPUS que se pueden utilizar (tenga cuidado con cosas como el modo de cálculo en Linux)
  2. La aplicación lanza un nuevo subproceso de host por GPU, pasando una ID de GPU. Cada hilo implícitamente / explícitamente llama al equivalente de cuCtxCreate () que pasa la ID de GPU que ha sido asignada
  3. ¡Lucro!

En Python, esto podría ser algo como esto:

import threading from pycuda import driver class gpuThread(threading.Thread): def __init__(self, gpuid): threading.Thread.__init__(self) self.ctx = driver.Device(gpuid).make_context() self.device = self.ctx.get_device() def run(self): print "%s has device %s, api version %s" / % (self.getName(), self.device.name(), self.ctx.get_api_version()) # Profit! def join(self): self.ctx.detach() threading.Thread.join(self) driver.init() ngpus = driver.Device.count() for i in range(ngpus): t = gpuThread(i) t.start() t.join()

Esto supone que es seguro establecer un contexto sin ninguna comprobación previa del dispositivo. Lo ideal es que compruebes el modo de cálculo para asegurarte de que sea seguro intentarlo, y luego uses un controlador de excepciones en caso de que el dispositivo esté ocupado. Pero espero que esto le dé la idea básica.