2011-09-23 17 views
6

Quiero entender cómo se crea un contexto de cuda y se asocia con un kernel en las aplicaciones API de tiempo de ejecución de cuda?Creación de contexto cuda y asociación de recursos en aplicaciones de API de tiempo de ejecución

Sé que las API del controlador lo hacen bajo el capó. Pero me gustaría entender la línea de tiempo de la creación.

Para empezar, sé que cudaRegisterFatBinary es la primera llamada hecha de cuda api y registra un archivo fatbin con el tiempo de ejecución. Le siguen un puñado de API de registro de funciones de cuda que llaman cuModuleLoad en la capa de controladores. Pero luego, si mi aplicación de API Cuda en tiempo de ejecución invoca cudaMalloc, ¿cómo se proporciona el puntero a esta función asociada con el contexto, que creo que debería haberse creado de antemano? ¿Cómo se maneja este contexto ya creado y se asocian las futuras llamadas API de tiempo de ejecución con él? Por favor desmitificar el funcionamiento interno.

Para citar la documentación de NVIDIA en este

CUDA API de ejecución llamadas operan en el CUcontext API controlador CUDA, que está obligado a el hilo host actual.

Si no existe CUDA CUcontext API conductor unido a la actual hilo en el momento de una llamada API de CUDA en tiempo de ejecución que requiere un CUcontext entonces el tiempo de ejecución de CUDA implícitamente crear un nuevo CUcontext antes de ejecutar la llamada.

Si el tiempo de ejecución de CUDA crea una CUcontext entonces el CUcontext habrá creado usando los parámetros especificados por la API de tiempo de ejecución de CUDA funciones cudaSetDevice, cudaSetValidDevices, cudaSetDeviceFlags, cudaGLSetGLDevice, cudaD3D9SetDirect3DDevice, cudaD3D10SetDirect3DDevice y cudaD3D11SetDirect3DDevice. Tenga en cuenta que estas funciones fallarán con cudaErrorSetOnActiveProcess si son llamadas cuando un CUcontext está vinculado al hilo de host actual.

La vida útil de un CUcontext se gestiona mediante un mecanismo de recuento de referencias . El recuento de referencia de un CUcontext se establece inicialmente en 0, y se incrementa en cuCtxAttach y disminuye en cuCtxDetach.

Si un CUcontext es creado por el tiempo de ejecución de CUDA, entonces el tiempo de ejecución de CUDA disminuirá el número de referencias de ese CUcontext en la función cudaThreadExit. Si un CUcontext es creado por la API de controlador de CUDA ( es creado por una instancia separada de la biblioteca API de CUDA Runtime), entonces el CUDA Runtime no incrementará o disminuirá el recuento de referencia de ese CUcontext.

Todos los estados de API CUDA Runtime (por ejemplo, direcciones de variables globales y valores ) viajan con su CUcontext subyacente. En particular, si un CUcontext se mueve de un hilo a otro (usando cuCtxPopCurrent y cuCtxPushCurrent), entonces todo el estado de la API CUDA Runtime se moverá a también.

Pero lo que no entiendo es cómo crea el contexto el tiempo de ejecución de cuda? ¿Qué llamadas API se utilizan para esto? ¿El compilador nvcc inserta algunas llamadas API para hacer esto en tiempo de compilación o se hace completamente en tiempo de ejecución? Si lo primero es cierto, ¿qué API de tiempo de ejecución se utilizan para esta gestión de contexto? Lo último es cierto cómo exactamente se hace?

Si un contexto está asociado con un hilo de host, ¿cómo obtenemos acceso a este contexto? ¿Está asociado automáticamente con todas las variables y referencias de puntero tratadas por el hilo?

¿cómo se realiza finalmente la carga de un módulo en el contexto?

Respuesta

3

El tiempo de ejecución de CUDA mantiene una lista global de módulos para cargar y agrega a esa lista cada vez que se carga en el proceso una DLL o .so que usa el tiempo de ejecución de CUDA. Pero los módulos no se cargan hasta que se crea un dispositivo.

La creación y la inicialización del contexto se realiza "perezosamente" por el tiempo de ejecución CUDA: cada vez que llamas a una función como cudaMemcpy(), comprueba si CUDA se ha inicializado y si no lo ha hecho crea un contexto (en el dispositivo previamente especificado por cudaSetDevice(), o el dispositivo predeterminado si nunca se llamó a cudaSetDevice() y carga todos los módulos. El contexto está asociado con ese subproceso de la CPU a partir de entonces, hasta que cudaSetDevice() lo cambie.

Puede utilizar las funciones de gestión de contexto/subproceso desde la API del controlador, como cuCtxPopCurrent()/cuCtxPushCurrent(), para utilizar el contexto de un subproceso diferente.

Puede llamar a cudaFree (0); para forzar esta inicialización perezosa a ocurrir.

Recomiendo encarecidamente hacerlo al momento de la inicialización de la aplicación, para evitar condiciones de carrera y comportamiento indefinido. Continúe y enumere e inicialice los dispositivos lo antes posible en su aplicación; Una vez hecho esto, en CUDA 4.0 puede llamar a cudaSetDevice() desde cualquier subproceso de CPU y seleccionará el contexto correspondiente creado por su código de inicialización.

+0

Intenté usar cudaFree (0). Pero todavía no tengo un contexto. CuCtxPop devolvió un nulo. ¿Por que es esto entonces? – ash

+0

Definitivamente debe tener un contexto actual después de un cudaFree exitoso (0). ¿Revisaste el valor de retorno? – ArchaeaSoftware

+0

Entonces, después de analizar el problema, descubrí que CudaFree (0) me está dando un error de manejo de recurso Inválido. ¿Tienes alguna idea de por qué? – ash

Cuestiones relacionadas