我想了解 cuda 上下文是如何在 cuda 运行时 API 应用程序中创建并与内核相关联的?
我知道它是由驱动程序 API 在后台完成的。但我想了解创作的时间线。
首先,我知道 cudaRegisterFatBinary 是第一个 cuda api 调用,它在运行时注册了一个 fatbin 文件。紧随其后的是一些在驱动层调用 cuModuleLoad 的 cuda 函数注册 API。但是,如果我的 Cuda 运行时 API 应用程序调用 cudaMalloc,那么提供给这个函数的指针是如何与上下文相关联的,我认为它应该是事先创建的。如何获得这个已经创建的上下文的句柄并将未来的运行时 API 调用与它相关联?请揭开内部运作的神秘面纱。
引用 NVIDIA 的文档
CUDA 运行时 API 调用在绑定到当前主机线程的 CUDA 驱动程序 API CUcontext 上运行。
如果在 CUDA Runtime API 调用时不存在绑定到当前线程的 CUDA Driver API CUcontext,则 CUDA Runtime 将在执行调用之前隐式创建一个新的 CUcontext。
如果 CUDA 运行时创建 CUcontext,则将使用 CUDA 运行时 API 函数 cudaSetDevice、cudaSetValidDevices、cudaSetDeviceFlags、cudaGLSetGLDevice、cudaD3D9SetDirect3DDevice、cudaD3D10SetDirect3DDevice 和 cudaD3D11SetDirect3DDevice 指定的参数创建 CUcontext。请注意,如果在 CUcontext 绑定到当前主机线程时调用这些函数,它们将失败并显示 cudaErrorSetOnActiveProcess。
CUcontext 的生命周期由引用计数机制管理。CUcontext 的引用计数最初设置为 0,并由 cuCtxAttach 递增并由 cuCtxDetach 递减。
如果 CUDA 运行时创建了 CUcontext,则 CUDA 运行时将在函数 cudaThreadExit 中减少该 CUcontext 的引用计数。如果一个 CUcontext 由 CUDA Driver API 创建(或由 CUDA Runtime API 库的单独实例创建),则 CUDA Runtime 不会增加或减少该 CUcontext 的引用计数。
所有 CUDA 运行时 API 状态(例如,全局变量的地址和值)都与它的底层 CUcontext 一起移动。特别是,如果 CUcontext 从一个线程移动到另一个线程(使用 cuCtxPopCurrent 和 cuCtxPushCurrent),那么所有 CUDA Runtime API 状态也将移动到该线程。
但我不明白的是 cuda 运行时如何创建上下文?为此使用了哪些 API 调用?nvcc 编译器是在编译时插入一些 API 调用来执行此操作,还是完全在运行时完成?如果前者是真的,那么什么运行时 API 用于此上下文管理?后者是真的,它究竟是如何完成的?
如果上下文与主机线程相关联,我们如何访问该上下文?它是否自动与线程处理的所有变量和指针引用相关联?
最终如何在上下文中完成模块加载?