gpt4 book ai didi

cuda - 如何为 CUDA 驱动程序 API 库实现句柄?

转载 作者:行者123 更新时间:2023-12-04 11:16:56 26 4
gpt4 key购买 nike

注意:问题已更新以解决评论中提出的问题,并强调问题的核心是关于 Runtime- 和 Driver API 之间的相互依赖关系

CUDA 运行时库(如 CUBLAS 或 CUFFT)通常使用“句柄”的概念来概括此类库的状态和上下文。使用模式非常简单:

// 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);

但是,关于这些句柄如何与驱动程序和运行时上下文以及多线程和设备进行互操作有许多微妙的细节。该文档列出了有关上下文处理的几个分散的详细信息:
  • CUDA 编程指南中上下文的一般描述,位于 http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#context
  • 处理多个上下文,如 http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html#multiple-contexts 处的 CUDA 最佳实践指南中所述
  • 运行时和驱动程序 API 之间的上下文管理差异,解释于 http://docs.nvidia.com/cuda/cuda-driver-api/driver-vs-runtime-api.html
  • CUBLAS 上下文/句柄的一般描述位于 http://docs.nvidia.com/cuda/cublas/index.html#cublas-context和他们的线程安全在 http://docs.nvidia.com/cuda/cublas/index.html#thread-safety2

  • 但是,有些信息似乎并不完全是最新的(例如,我认为应该使用 cuCtxSetCurrent 而不是 cuCtxPushCurrentcuCtxPopCurrent ?),其中一些似乎来自“Primary上下文”处理是通过驱动程序 API 公开的,有些部分过于简化,因为它们只显示最简单的使用模式,只对多线程做出模糊或不完整的陈述,或者不能应用于运行时库。

    我的目标是实现一个运行时库,它提供自己的“句柄”类型,并允许在上下文处理和线程安全方面与其他运行时库等效的使用模式。

    对于库可以单独使用 Runtime API 在内部实现的情况,事情可能很清楚:上下文管理完全由用户负责。如果他创建了自己的驱动程序上下文,则遵循 documentation about the Runtime- and Driver context management 中规定的规则。将应用。否则,运行时 API 函数将负责处理主要上下文。

    但是,可能存在库在内部必须使用驱动程序 API 的情况。例如,为了将 PTX 文件加载为 CUmodule对象,并获得 CUfunction他们的对象。当库应该 - 对于用户 - 表现得像运行时库,但在内部必须使用驱动程序 API 时,会出现一些关于如何“在幕后”实现上下文处理的问题。

    到目前为止我想出的东西在这里勾勒出来。

    (它是“伪代码”,因为它省略了错误检查和其他细节,而且......所有这些都应该用 Java 实现,但这不应该在这里相关)

    1. “句柄”基本上是一个包含以下信息的类/结构:
    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 句柄相同的行为。但是我彻底测试这个的可能性是有限的,因为我只有一个设备,因此无法测试关键情况,例如有两个上下文,一个用于两个设备中的每一个。

    所以我的问题是:
  • 是否有任何既定的模式来实现这样的“句柄”?
  • 是否有任何使用模式(例如,多个设备和每个设备一个上下文)无法用上面概述的方法覆盖,但会被 CUBLAS 的“句柄”实现覆盖?
  • 更一般地说:是否有任何关于如何改进当前“处理”实现的建议?
  • 修辞:CUBLAS 句柄处理的源代码是否在某处可用?

  • (我还查看了 context handling in tensorflow ,但我不确定是否可以从中得出有关如何为运行时库实现句柄的建议......)

    (此处已删除“更新”,因为它是针对评论添加的,不应再相关)

    最佳答案

    很抱歉我没有早点注意到这个问题——因为我们可能在这方面有所合作。另外,我不太清楚这个问题是属于这里的,在 codereview.SX 上还是在程序员.SX 上,但让我们忽略所有这些。
    我现在已经完成了你想要做的事情,而且可能更普遍。因此,我可以提供一个如何处理“句柄”的示例,此外,我还提出了根本不必实现这一点的前景。
    该库是 cuda-api-wrappers 的扩展还包括驱动程序 API 和 NVRTC;它尚未发布级,但处于测试阶段,在 this branch .
    现在,回答你的具体问题:
    围绕原始“句柄”编写类的模式

    Are there any established patterns for implementing such a "Handle"?


    是的。如果你阅读:
    What is the difference between: Handle, Pointer and Reference
    您会注意到句柄被定义为“对对象的不透明引用”。它与指针有一些相似之处。因此,相关模式是 PIMPL idiom 的变体。 : 在常规的 PIMPL 中,你写一个实现类,向外的类只持有一个指向实现类的指针,并将方法调用转发给它。当您在某些第三方库或驱动程序中有一个不透明对象的不透明句柄时 - 您可以使用该句柄将方法调用转发到该实现。
    这意味着, 您的外向类不是句柄,它代表您拥有句柄的对象。
    通用性和灵活性

    Are there any usage patterns (e.g. with multiple devices and one context per device) that could not be covered with the approach that is sketched above, but would be covered with the "handle" implementations of CUBLAS?


    我不确定 CUBLAS 在幕后到底做了什么(说实话,我几乎从未使用过 CUBLAS),但如果它设计和实现得很好,它会
    创建自己的上下文,并尽量不影响您的代码的其余部分,即它总是这样做:
  • 将我们的 CUBLAS 上下文推送到堆栈顶部
  • 做实际工作
  • 弹出上下文堆栈的顶部。

  • 你的类(class)不这样做。

    More generally: Are there any recommendations of how to improve the current "Handle" implementation?


    是的:
  • 只要可能且相关,就使用 RAII。如果您的创建代码分配了资源(例如通过 CUDA 驱动程序) - 您返回的对象的析构函数应该安全地释放这些资源。
  • 允许引用类型和值类型使用句柄,即它可能是我创建的句柄,但它也可能是我从其他地方得到的句柄,不是我的责任。如果您让用户释放资源,这是微不足道的,但如果您承担这个责任,这有点棘手
  • 您假设如果有任何当前上下文,那就是您的句柄需要使用的上下文。谁说的?至少,如果用户愿意,让他们传入上下文。
  • 除非你真的必须,否则避免自己编写这个的低级部分。您很可能会遗漏一些事情(push-and-pop 并不是您可能遗漏的唯一事情),并且您正在重复许多实际上是通用的工作,而不是特定于您的应用程序或库的工作。我可能在这里有偏见,但您现在可以使用漂亮的、RAII 风格的 CUDA 上下文、流、模块、设备等包装器,甚至不知道任何东西的原始句柄。

  • Rhetorical: Is the source code of the CUBLAS handle handling available somewhere?


    据我所知,NVIDIA 还没有发布它。

    关于cuda - 如何为 CUDA 驱动程序 API 库实现句柄?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48676001/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com