我想了解如何在cuda运行时API应用程序中创建cuda上下文并与内核相关联?
我知道它是由驱动程序api在底层完成的。但我想知道创作的时间线。
首先,我知道cudaRegisterFatBinary是第一个cuda api调用,它在运行时注册了一个fatbin文件。接下来是一些cuda函数注册api,它们在驱动层调用cuModuleLoad。但是,如果我的Cuda运行时API应用程序调用cudaMalloc,如何提供与上下文相关的该函数的指针,我认为应该事先创建。如何获得这个已经创建的上下文的句柄并将未来的运行时API调用与它关联?请揭开内部工作原理。
在此引用NVIDIA的文档
CUDA运行时API调用在CUDA驱动程序API CUcontext上操作绑定到当前主机线程。
如果没有CUDA驱动程序API CUcontext绑定到当前线程在CUDA运行时API调用时需要一个那么CUDA运行时将隐式地创建一个新的CUcontext
如果CUDA运行时创建了一个CUcontext,那么CUcontext将被使用CUDA运行时API指定的参数创建函数cudaSetDevice, cudaSetValidDevices, cudaSetDeviceFlagscudaGLSetGLDevice cudaD3D9SetDirect3DDevice,cudaD3D10SetDirect3DDevice和cudaD3D11SetDirect3DDevice。请注意,如果是,这些函数将使用cudaErrorSetOnActiveProcess失败当一个CUcontext被绑定到当前主机线程时调用。
CUcontext的生命周期是通过引用计数来管理的机制。CUcontext的引用计数最初设置为0,并且由cuCtxAttach递增,由cuCtxDetach递减。
如果一个CUcontext是由CUDA Runtime创建的,那么CUDA Runtime会减少函数中该CUcontext的引用计数吗cudaThreadExit。如果CUcontext是由CUDA驱动程序API(或是由CUDA运行时API库的单独实例创建的),那么CUDA运行时将不会增加或减少引用
所有CUDA运行时API状态(例如,全局变量的地址和值)与其底层的CUcontext一起传播。特别地,如果aCUcontext从一个线程移动到另一个线程(使用cuCtxPopCurrent)和cuCtxPushCurrent),那么所有CUDA运行时API状态将移动到
但是我不明白的是cuda运行时是如何创建上下文的?这使用了什么API调用?nvcc编译器是否在编译时插入一些API调用来执行此操作,或者完全在运行时完成?如果前者是正确的,那么该上下文管理使用哪些运行时api ?如果后者是真的,它究竟是如何完成的?
如果一个上下文与一个宿主线程相关联,我们如何访问这个上下文?它是否自动与线程处理的所有变量和指针引用相关联?
最终如何在上下文中完成模块加载?
CUDA运行时维护要加载的模块的全局列表,并在每次将使用CUDA运行时的DLL或.so加载到进程中时添加该列表。但是在设备创建之前,这些模块实际上是不会被加载的。
上下文创建和初始化是由CUDA运行时"惰性"完成的-每次调用cudaMemcpy()之类的函数时,它都会检查CUDA是否已初始化,如果没有,它会创建一个上下文(在先前由cudaSetDevice()指定的设备上,或者在cudaSetDevice()从未调用的默认设备上)并加载所有模块。上下文从那时起与该CPU线程关联,直到它被cudaSetDevice()更改。
你可以使用来自驱动API的上下文/线程管理函数,例如cuCtxPopCurrent()/cuCtxPushCurrent(),来使用来自不同线程的上下文。
你可以调用cudaFree(0);强制执行此延迟初始化。
我强烈建议在应用程序初始化时这样做,以避免竞争条件和未定义的行为。继续,在你的应用中尽可能早地枚举和初始化这些设备;一旦完成,在CUDA 4.0中,你可以从任何CPU线程调用cudaSetDevice(),它将选择由初始化代码创建的相应上下文。