PyCUDA + Threading = Manijas no válidas en invocaciones del kernel

Intentaré aclarar esto;

Tengo dos clases; GPU(Object) , para el acceso general a la funcionalidad de GPU, y multifunc(threading.Thread) para una función en particular, estoy tratando de configurar varios dispositivos. GPU contiene la mayor parte del procesamiento ‘por primera vez’ necesario para todas las subsecuencias de uso subsiguientes, por lo que la GPU recibe una llamada de la función multifunc con su self instancia pasada como un argumento __init__ (junto con las colas habituales y __init__ ).

Desafortunadamente, multifunc craps a cabo con:

 File "/home/bolster/workspace/project/gpu.py", line 438, in run prepare(d_A,d_B,d_XTG,offset,grid=N_grid,block=N_block) File "/usr/local/lib/python2.7/dist-packages/pycuda-0.94.2-py2.7-linux-x86_64.egg/pycuda/driver.py", line 158, in function_call func.set_block_shape(*block) LogicError: cuFuncSetBlockShape failed: invalid handle 

El primer puerto de llamada fue, por supuesto, las dimensiones del bloque, pero están dentro del rango (el mismo comportamiento, incluso si fuerzo el block=(1,1,1) , también la cuadrícula.

Básicamente, dentro de multifunc , todas las funciones usuales de CUDA memalloc, etc. funcionan bien, (lo que implica que no es un problema de contexto). Por lo tanto, el problema debe estar en el SourceModule de origen de la función del núcleo.

Tengo una plantilla de kernel que contiene todo mi código CUDA que está a nivel de archivo, y las plantillas se realizan con jinja2 en la inicialización de GPU . Independientemente de si el objeto con plantilla se convierte en un objeto SourceModule en GPU y se pasa a multifunc , o si se convierte en multifunc , sucede lo mismo.

Google ha sido en gran parte inútil para este problema en particular, pero después de la stack, Invalid Handle se hace referencia a la Invalid Handle como la Invalid Handle de la función del kernel en lugar de que haya algo extraño en las dimensiones del bloque.

Soy consciente de que esta es una situación muy complicada, pero estoy seguro de que alguien puede ver un problema que me he perdido.

La razón es la afinidad del contexto. Cada instancia de la función CUDA está vinculada a un contexto, y no son portátiles (lo mismo se aplica a las asignaciones de memoria y las referencias de textura). Por lo tanto, cada contexto debe cargar la instancia de la función por separado y luego usar el identificador de la función devuelto por esa operación de carga.

Si no está usando metaprogtwigción en absoluto, puede que le resulte más sencillo comstackr su código CUDA en un archivo cubin, y luego cargar las funciones que necesita de cubin en cada contexto con driver.module_from_file . Cortar y pegar directamente de un código de producción mío:

 # Context establishment try: if (autoinit): import pycuda.autoinit self.context = None self.device = pycuda.autoinit.device self.computecc = self.device.compute_capability() else: driver.init() self.context = tools.make_default_context() self.device = self.context.get_device() self.computecc = self.device.compute_capability() # GPU code initialization # load pre compiled CUDA code from cubin file # Select the cubin based on the supplied dtype # cubin names contain C++ mangling because of # templating. Ugly but no easy way around it if self.computecc == (1,3): self.fimcubin = "fim_sm13.cubin" elif self.computecc[0] == 2: self.fimcubin = "fim_sm20.cubin" else: raise NotImplementedError("GPU architecture not supported") fimmod = driver.module_from_file(self.fimcubin) IterateName32 = "_Z10fimIterateIfLj8EEvPKT_PKiPS0_PiS0_S0_S0_jjji" IterateName64 = "_Z10fimIterateIdLj8EEvPKT_PKiPS0_PiS0_S0_S0_jjji" if (self.dtype == np.float32): IterateName = IterateName32 elif (self.dtype == np.float64): IterateName = IterateName64 else: raise TypeError self.fimIterate = fimmod.get_function(IterateName) except ImportError: warn("Could not initialise CUDA context") 

Típico; Tan pronto como escribo la pregunta, la resuelvo.

El problema era que SourceModule operaba fuera de un contexto activo. Para solucionarlo moví la invocación de SourceModule a la función de ejecución en el hilo, debajo de la configuración del contexto cuda.

Dejando esto por un tiempo porque estoy seguro de que alguien más tiene una mejor explicación!