如何将 cuda 驱动程序 api 与 cuda 运行时 api 混合使用?

Posted

技术标签:

【中文标题】如何将 cuda 驱动程序 api 与 cuda 运行时 api 混合使用?【英文标题】:how can I mix cuda driver api with cuda runtime api? 【发布时间】:2020-05-24 17:03:00 【问题描述】:

来自cuda document 声明:

    如果通过驱动程序 API 创建上下文并使其成为当前上下文,则后续运行时调用将获取此上下文,而不是创建新上下文。 如果运行时已初始化(在 CUDA 运行时中隐含提及),可使用 cuCtxGetCurrent() 检索初始化期间创建的上下文。后续驱动程序 API 调用可以使用此上下文。

我可以使第一点起作用。我可以从 cuda 驱动程序创建上下文。然后我可以使用 cuda 运行时函数而不调用 cudaSetDevice(),这会隐式创建一个新的主上下文。

但是,我想通过第二个选项工作。那就是先初始化运行时然后执行cuCtxGetCurrent() 并在 cuda 驱动程序 api 中使用它。这根本不起作用。我总是提出错误说上下文已被破坏或无效。我做错了什么?

这是我的示例代码:

#define CUDA_DRIVER_API
#include <cuda.h>
#include <cuda_runtime.h>
#include <helper_cuda.h>
#include <iostream>
CUcontext check_current_ctx()

    CUcontext context0;
    unsigned int api_ver;
    checkCudaErrors(cuCtxGetCurrent(&context));
    fprintf(stdout, "current context=%p\n", context);
    checkCudaErrors( cuCtxGetApiVersion(context, &api_ver));
    fprintf(stdout, "current context api version = %d\n", api_ver);
    return context;

auto inital_runtime_context()

    int current_device = 0;
    int device_count = 0;
    int devices_prohibited = 0;
    CUcontext current_ctx0;

    cudaDeviceProp deviceProp;
    checkCudaErrors(cudaGetDeviceCount(&device_count));;
    if (device_count == 0) 
        fprintf(stderr, "CUDA error: no devices supporting CUDA.\n");
        exit(EXIT_FAILURE);
    

    // Find the GPU which is selected by Vulkan
    while (current_device < device_count) 
        cudaGetDeviceProperties(&deviceProp, current_device);
        if ((deviceProp.computeMode != cudaComputeModeProhibited)) 
            checkCudaErrors(cudaSetDevice(current_device));
            checkCudaErrors(cudaGetDeviceProperties(&deviceProp, current_device));
            printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n",
                current_device, deviceProp.name, deviceProp.major,
                deviceProp.minor);
            CUcontext current_ctx;
            cuCtxGetCurrent(&current_ctx);
            std::cout << "current_ctx=" << current_ctx << "\n";
            return current_device;

         else 
            devices_prohibited++;
        

        current_device++;
    

    if (devices_prohibited == device_count) 
        fprintf(stderr,
            "CUDA error:"
            " No Vulkan-CUDA Interop capable GPU found.\n");
        exit(EXIT_FAILURE);
    

    return -1;

void test_runtime_driver_op()

    inital_runtime_context();
    check_current_ctx();


它报告:

GPU Device 0: "GeForce RTX ..." with compute capability 7.5

current_ctx=0x6eb220
current context=0x6eb220
CUDA error at ... code=201(CUDA_ERROR_INVALID_CONTEXT) "cuCtxGetApiVersion(context, &api_ver)" 

【问题讨论】:

您可能需要实际包含一个 API 调用,如 cudafree(0) 以使运行时 API 创建一个上下文。您现有的代码可能不会强制创建惰性上下文 @talonmies 非常感谢!这真的有效。但是那文件有错吗?由于从文档中, cudaSetDevice() 应该已经创建了 cuda 上下文。你能把这个总结为答案吗?那我就接受了。 我不认为文档是错误的,但是在运行时 API 中创建上下文的确切时间和方式一直有点模棱两可 为您提供进一步的“轻读”:How do the CUDA Runtime's current device and the driver context stack interact? 【参考方案1】:

您收到错误的原因是,至少在这种情况下,当您尝试使用驱动程序 API 绑定到上下文时,没有发生延迟运行时 API 上下文创建。确保您获得使用运行时创建的上下文的规范方法一直是

cudaSetDevice(current_device);
cudaFree(0);

文档在这一点上一直模棱两可,语义似乎随着时间的推移发生了微妙的变化,但这种调用一直对我有用。

【讨论】:

【参考方案2】:

@talonmies 的答案是正确的,从某种意义上说它会起作用,但是 - 如果你想从 driver 方面纠正问题,你可以尝试类似:

// ...
CUcontext check_current_ctx()

    CUcontext context0;
    checkCudaErrors( cuCtxGetCurrent(&context) );
    CUdevice device;
    checkCudaErrors( cuCtxGetDevice(&device) );
    CUcontext primary_context;
    checkCudaErrors( cuDevicePrimaryCtxRetain(&primary_context, device) );
    unsigned int flags;
    int active;
    CUresult primary_state_check_result = 
        cuDevicePrimaryCtxGetState(device, unsigned &flags, &active);

    // etc. etc.

现在您可以检查了:

    当前设备的当前上下文是否是主要的(= 运行时 API 的上下文)。 主上下文是否已初始化(通过比较 primary_state_check_resultCUDA_ERROR_DEINITIALIZEDCUDA_ERROR_NOT_INITIALIZED)。

然后尝试获取 API 版本。


我还应该提到,我编写了一个 C++ 包装层,它涵盖了两个驱动程序和运行时 API,并允许无缝使用这两者;请参阅 cuda-api-wrappers 库的 this branch。它们尚未发布(截至撰写本文时),但非常欢迎您试一试。

【讨论】:

以上是关于如何将 cuda 驱动程序 api 与 cuda 运行时 api 混合使用?的主要内容,如果未能解决你的问题,请参考以下文章

我应该如何以及何时将倾斜指针与 cuda API 一起使用?

AMD 相当于 CUDA 驱动程序 API?

将 CUDA-gdb 与 NVRTC 一起使用

将 cv::cuda::GpuMat 与推力和测试推力 API 一起使用时出现问题

等效于 cudaSetDevice 的 CUDA 驱动程序 API

如何在没有主机编译器的情况下创建 Cuda 模块