注意:问题已经更新,以解决评论中提出的问题,并强调问题的核心是关于运行时和驱动程序API之间的相互依赖性 < / p>
CUDA运行时库(如CUBLAS或CUFFT)通常使用&#34; handle&#34;总结了这种图书馆的状态和背景。使用模式非常简单:
// Create a handle
cublasHandle_t handle;
cublasCreate(&handle);
// Call some functions, always passing in the handle as the first argument
cublasSscal(handle, ...);
// When done, destroy the handle
cublasDestroy(handle);
但是,有许多关于这些句柄如何与Driver-和Runtime上下文以及多个线程和设备进行互操作的细微细节。该文档列出了有关上下文处理的若干分散细节:
“{3}}
处理多个上下文,如http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#context
运行时和驱动程序API之间的上下文管理差异,在http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html#multiple-contexts
http://docs.nvidia.com/cuda/cuda-driver-api/driver-vs-runtime-api.html处CUBLAS上下文/句柄的一般说明及http://docs.nvidia.com/cuda/cublas/index.html#cublas-context处的线程安全
但是,有些信息似乎并不完全是最新的(例如,我认为应该使用cuCtxSetCurrent
代替cuCtxPushCurrent
和cuCtxPopCurrent
?),其中一些似乎来自&#34;主要背景&#34;之前的时间处理是通过驱动程序API公开的,有些部分过于简单,因为它们只显示最简单的使用模式,只做出关于多线程的模糊或不完整的陈述,或者不能应用于&#34; handle&#34;在运行时库中使用。
我的目标是实现一个运行时库,它提供了自己的&#34;句柄&#34;类型,并允许在上下文处理和线程安全方面与其他运行时库等效的使用模式。
对于只能使用 Runtime API 在内部实现库的情况,事情可能很清楚:上下文管理完全由用户负责。如果他创建了自己的驱动程序上下文,则http://docs.nvidia.com/cuda/cublas/index.html#thread-safety2中规定的规则将适用。否则,Runtime API函数将负责处理主要上下文。
但是,可能存在库内部必须使用驱动程序API 的情况。例如,为了将PTX文件加载为CUmodule
个对象,并从中获取CUfunction
个对象。当库应该 - 对于用户 - 表现就像 Runtime 库一样,但内部必须使用 Driver API时,会出现一些问题如何实施上下文处理&#34;引擎盖&#34;。
到目前为止,我想到的是草图。
(它是&#34;伪代码&#34;因为它省略了错误检查和其他细节,并且......所有这些都应该用Java实现,但这里不应该相关) 子>
1。&#34;处理&#34;基本上是一个包含以下信息的类/结构:
class Handle
{
CUcontext context;
boolean usingPrimaryContext;
CUdevice device;
}
2. 创建它时,必须涵盖两种情况:当驱动程序上下文对于调用线程是最新的时,可以创建它。在这种情况下,它应该使用此上下文。否则,它应该使用当前(运行时)设备的主要上下文:
Handle createHandle()
{
cuInit(0);
// Obtain the current context
CUcontext context;
cuCtxGetCurrent(&context);
CUdevice device;
// If there is no context, use the primary context
boolean usingPrimaryContext = false;
if (context == nullptr)
{
usingPrimaryContext = true;
// Obtain the device that is currently selected via the runtime API
int deviceIndex;
cudaGetDevice(&deviceIndex);
// Obtain the device and its primary context
cuDeviceGet(&device, deviceIndex);
cuDevicePrimaryCtxRetain(&context, device));
cuCtxSetCurrent(context);
}
else
{
cuCtxGetDevice(device);
}
// Create the actual handle. This might internally allocate
// memory or do other things that are specific for the context
// for which the handle is created
Handle handle = new Handle(device, context, usingPrimaryContext);
return handle;
}
3. 在调用库的内核时,关联句柄的上下文对于调用线程是最新的:
void someLibraryFunction(Handle handle)
{
cuCtxSetCurrent(handle.context);
callMyKernel(...);
}
在这里,有人可能会争辩说调用者负责确保所需的上下文是最新的。但是,如果为主上下文创建句柄,则此上下文将自动生成。
4. 当句柄被销毁时,这意味着必须调用cuDevicePrimaryCtxRelease
,但当上下文是主要上下文时仅:
void destroyHandle(Handle handle)
{
if (handle.usingPrimaryContext)
{
cuDevicePrimaryCtxRelease(handle.device);
}
}
从我的实验到目前为止,这个似乎来公开与CUBLAS句柄相同的行为,例如。但是我彻底测试它的可能性是有限的,因为我只有一个设备,因此无法测试关键的情况,例如有两个上下文,一个用于两个设备。
所以我的问题是:
(我也看过documentation about the Runtime- and Driver context management,但我不确定是否可以从中获取有关如何为运行时库实现句柄的建议......)
(An&#34;更新&#34;已在此处删除,因为它是为了回应评论而添加的,并且不再相关)
答案 0 :(得分:1)
很抱歉,我没有很快注意到这个问题-因为我们可能在此问题上进行了一些合作。另外,对于我来说,这个问题是否属于codereview.SX还是程序员.SX还不是很清楚,但让我们忽略所有这些问题。
我现在已经完成了您打算做的工作,而且可能更笼统了。因此,我既可以提供有关处理“句柄”的示例,也可以建议完全不必实现此句柄的前景。
该库是cuda-api-wrappers的扩展,也涵盖了驱动程序API和NVRTC;它尚未发布,但仍处于测试阶段this branch。
现在,回答您的具体问题:
是否存在用于实现这种“句柄”的既定模式?
是的。如果您阅读:
What is the difference between: Handle, Pointer and Reference
您会注意到一个句柄被定义为“对对象的不透明引用”。它与指针有一些相似之处。因此,一个相关的模式是PIMPL idiom的变体:在常规PIMPL中,您编写了一个实现类,而面向外部的类仅持有指向该实现类的指针,并转发对其的方法调用。如果某些第三方库或驱动程序中的不透明对象具有不透明的句柄,则可以使用该句柄将方法调用转发给该实现。
这意味着您的面向外部的类不是手柄,它表示您拥有手柄的对象。
是否存在上面概述的方法无法涵盖的使用模式(例如,具有多个设备且每个设备一个上下文),但将由CUBLAS的“句柄”实现覆盖?
我不确定CUBLAS到底是做什么的(老实说,我几乎从未使用过CUBLAS),但是如果设计和实施得当,它会 创建自己的上下文,并尽量不影响其余的代码,即可以:
您的班级不这样做。
更笼统地说:是否有关于如何改进当前“句柄”实现的建议?
是:
修饰语:CUBLAS句柄处理的源代码在某处可用吗?
据我所知,NVIDIA尚未发布它。