检测不带CUDA的NVIDIA显卡

7
我希望能够提取关于NVIDIA GPU的有限信息,而无需链接CUDA库。唯一需要的信息是计算能力和GPU名称,更多信息可能有用但不是必需的。代码应该用C(或C ++)编写。这些信息将在配置时(当CUDA工具包不可用时)和运行时(当执行的二进制文件未编译为CUDA支持时)使用,以提示用户系统中存在支持的GPU。
据我了解,这可以通过驱动程序API实现,但我对所需的技术细节并不熟悉。因此,我的问题是:
- 至少满足上述最低要求需要采取哪些确切步骤? - 是否有这样的开源代码可用?
请注意,我的第一步是Linux上的某些代码,但最终我需要跨平台的代码。考虑到CUDA的平台可用性,对于完整的解决方案,这将涉及Linux、Mac OS和Windows平台上的x86 / AMD64代码(至少目前是这样,列表可能很快扩展到ARM)。
编辑
我所说的“可以通过驱动程序API实现”是指应该能够动态加载libcuda.so并通过驱动程序API查询设备属性。但我不确定具体的细节。

你有没有考虑过使用 Tesla Deployment kit (其中包含了你所提到的查询的源代码示例,但有一些限制)? - Robert Crovella
CUDA SDK中包含一个deviceQueryDrvAPI示例(从CUDA 5.0开始,也包含在CUDA Toolkit发行版中)。这个示例向你展示了如何使用驱动程序API查询所需信息。但是所有建议的解决方案都需要“链接CUDA库”。我猜你只是不想链接CUDA运行时API库(cudart),因为这会要求你分发cudart共享库。 - harrism
@RobertCrovella:我指的是libnvidia-ml.so库,我没有意识到它已经包含在所有最新的驱动程序中。然而,nvml无法提供一个重要的信息:计算能力。 - pszilard
@8bitwide:仅仅因为如果一个二进制文件没有使用CUDA编译,但在一台带有GPU的机器上运行,我想告诉用户重新编译可能是值得考虑的。 - pszilard
@pszilard 我能想到的最好方法是使用DirectX或OpenGL检查GPU型号,并将其与已知列表进行比较。当然,这并不是最佳选择。据我所知,Nvidia没有在SDK之外公开任何CUDA API,因此您有两个选择。从SDK中提取countcudedevice()函数(可能只需要几个头文件和DLL),或者进行深入研究并编写自己的实现。 - 8bitwide
显示剩余5条评论
4个回答

9
很遗憾,NVML无法提供有关设备计算能力的信息。
你需要做的是:
  1. 手动加载CUDA库(应用程序未链接到libcuda)
    • 如果库不存在,则CUDA驱动程序未安装
  2. 在库中查找必要函数的指针
  3. 使用驱动程序API查询有关可用GPU的信息
我希望这段代码对你有所帮助。 我已在Linux下测试过它,但稍作修改后也应该可以在Windows下编译。
#include <cuda.h>
#include <stdio.h>

#ifdef WINDOWS
#include <Windows.h>
#else
#include <dlfcn.h>
#endif


void * loadCudaLibrary() {
#ifdef WINDOWS
    return LoadLibraryA("nvcuda.dll");
#else
    return dlopen ("libcuda.so", RTLD_NOW);
#endif
}

void (*getProcAddress(void * lib, const char *name))(void){
#ifdef WINDOWS
    return (void (*)(void)) GetProcAddress(lib, name);
#else
    return (void (*)(void)) dlsym(lib,(const char *)name);
#endif
}

int freeLibrary(void *lib)
{
#ifdef WINDOWS
    return FreeLibrary(lib);
#else
    return dlclose(lib);
#endif
}

typedef CUresult CUDAAPI (*cuInit_pt)(unsigned int Flags);
typedef CUresult CUDAAPI (*cuDeviceGetCount_pt)(int *count);
typedef CUresult CUDAAPI (*cuDeviceComputeCapability_pt)(int *major, int *minor, CUdevice dev);

int main() {
    void * cuLib;
    cuInit_pt my_cuInit = NULL;
    cuDeviceGetCount_pt my_cuDeviceGetCount = NULL;
    cuDeviceComputeCapability_pt my_cuDeviceComputeCapability = NULL;

    if ((cuLib = loadCudaLibrary()) == NULL)
        return 1; // cuda library is not present in the system

    if ((my_cuInit = (cuInit_pt) getProcAddress(cuLib, "cuInit")) == NULL)
        return 1; // sth is wrong with the library
    if ((my_cuDeviceGetCount = (cuDeviceGetCount_pt) getProcAddress(cuLib, "cuDeviceGetCount")) == NULL)
        return 1; // sth is wrong with the library
    if ((my_cuDeviceComputeCapability = (cuDeviceComputeCapability_pt) getProcAddress(cuLib, "cuDeviceComputeCapability")) == NULL)
        return 1; // sth is wrong with the library

    {
        int count, i;
        if (CUDA_SUCCESS != my_cuInit(0))
            return 1; // failed to initialize
        if (CUDA_SUCCESS != my_cuDeviceGetCount(&count))
            return 1; // failed

        for (i = 0; i < count; i++)
        {
            int major, minor;
            if (CUDA_SUCCESS != my_cuDeviceComputeCapability(&major, &minor, i))
                return 1; // failed

            printf("dev %d CUDA compute capability major %d minor %d\n", i, major, minor);
        }
    }
    freeLibrary(cuLib);
    return 0; 
}

在Linux上测试:

$ gcc -ldl main.c
$ ./a.out
dev 0 CUDA compute capability major 2 minor 0
dev 1 CUDA compute capability major 2 minor 0

在没有CUDA驱动程序的Linux上进行测试

$ ./a.out
$ echo $?
1

干杯


谢谢,这看起来很有前途!现在唯一的问题是这段代码包括cuda.h,而我的目标是在配置时编译这么小的一段代码,检查兼容硬件,并警告用户是否发现了任何有用的东西。因此,假定CUDA工具包未安装在主机上。我在SDK中找到了一个cuda_drvapi_dynlink_cuda.h。从中提取所需的代码应该可以完成任务,我需要弄清楚的唯一一件事就是许可证(必须与LGPL兼容)。 - pszilard
你不能将这个应用程序作为二进制文件发布吗?它只需要使用C编译器进行编译,因此您不会遇到任何CLI不兼容问题,就像使用C ++一样(CUDA运行时API需要C ++编译器但不需要CUDA驱动程序API)。我不确定在配置时间编译此应用程序的要求来自哪里。 - Przemyslaw Zych
不,我不能。这是一种科学的HPC代码,可以在从上网本到最大的超级计算机等几乎所有硬件上编译。一个重要的方面是避免用户需要解决十几个错误消息(包括缺少CUDA工具包),并且只在配置或运行时检测到支持的设备时警告用户。 - pszilard
我的意思是,你不能发布一个搜索CUDA设备的应用程序作为二进制文件吗?它可以使用gcc编译,并且在任何机器上都可以工作,而无需重新编译。只需在配置步骤中运行此发现应用程序即可。 - Przemyslaw Zych
在Windows 10上,我不需要cuda.h包含文件,上述示例可以正常工作。 - mungflesh
(但是类型CUresult和CUdevice需要定义) - mungflesh

1
我通过使用并静态链接CUDA 6.0 SDK来解决了这个问题。这会产生一个应用程序,也可以在没有NVIDIA卡或未安装SDK的机器上正常工作。在这种情况下,它将指示没有CUDA可用设备。
CUDA SDK中包含的示例中有一个名为deviceQuery的示例 - 我使用其中的片段编写了以下代码。我确定是否存在CUDA可用设备,如果存在,则确定具有最高计算能力的设备。
#include <cuda_runtime.h>

struct GpuCap
{
    bool QueryFailed;           // True on error
    int  DeviceCount;           // Number of CUDA devices found 
    int  StrongestDeviceId;     // ID of best CUDA device
    int  ComputeCapabilityMajor; // Major compute capability (of best device)
    int  ComputeCapabilityMinor; // Minor compute capability
};

GpuCap GetCapabilities()
{
    GpuCap gpu;
    gpu.QueryFailed = false;
    gpu.StrongestDeviceId = -1;
    gpu.ComputeCapabilityMajor = -1;
    gpu.ComputeCapabilityMinor = -1;

    cudaError_t error_id = cudaGetDeviceCount(&gpu.DeviceCount);
    if (error_id != cudaSuccess)
    {
        gpu.QueryFailed = true;
        gpu.DeviceCount = 0;    
        return gpu;
    }

    if (gpu.DeviceCount == 0)
        return gpu; // "There are no available device(s) that support CUDA

    // Find best device
    for (int dev = 0; dev < gpu.DeviceCount; ++dev)
    {
        cudaDeviceProp deviceProp;
        cudaGetDeviceProperties(&deviceProp, dev);
        if (deviceProp.major > gpu.ComputeCapabilityMajor)
        {
            gpu.ComputeCapabilityMajor = dev;
            gpu.ComputeCapabilityMajor = deviceProp.major;
            gpu.ComputeCapabilityMinor = 0;
        }
        if (deviceProp.minor > gpu.ComputeCapabilityMinor)
        {
            gpu.ComputeCapabilityMajor = dev;
            gpu.ComputeCapabilityMinor = deviceProp.minor;
        }
    }
    return gpu;
}

感谢分享。然而,这需要在编译时可用 CUDA 运行时,这正是我最初想要避免的。如今,CUDA已经更加广泛地可用,因此原始要求已经改变,现在我们假设用户知道他们有GPU,并且需要CUDA工具包来使用它。 - pszilard

1

1

首先,我认为NVIDIA NVML是您正在寻找的API。其次,有一个基于NVML的开源项目,称为PAPI NVML


谢谢。正如我在上面的评论中提到的,NVIDIA NVML不是一个好的选择,因为据我所知它不提供有关计算能力的信息。我会看看PAPI NVML,但我怀疑它也不会提供这些信息。 - pszilard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接