检测没有CUDA的NVIDIA GPU

时间:2012-10-10 21:14:33

标签: c cuda

我想提取一组有关NVIDIA GPU的信息,而不需要链接到CUDA库。 所需的唯一信息是计算能力和GPU的名称,超过这个可能是有用的但不是必需的。代码应该用C(或C ++)编写。这些信息将在配置时(当CUDA工具包不可用时)和运行时(当执行的二进制文件未使用CUDA支持编译时)使用,以向用户建议系统中存在受支持的GPU。 / p>

据我了解,这可以通过驱动程序API实现,但我不太熟悉这需要的技术细节。所以我的问题是:

  • 至少满足最低要求的具体步骤是什么(见上文);

  • 是否有这样的开源代码?

请注意,我的第一步是为Linux提供一些代码,但最终我需要与平台无关的代码。考虑到CUDA的平台可用性,对于完整的解决方案,这将涉及适用于Linux,Mac OS和Windows的x86 / AMD64代码(至少目前,该列表很快将通过ARM扩展)。

修改

我的意思是“它可以通过驱动程序API”是一个应该能够动态加载libcuda.so并通过驱动程序API查询设备属性。不过,我不确定细节。

4 个答案:

答案 0 :(得分:7)

不幸的是,NVML不提供有关设备计算功能的信息。

您需要做的是:

  1. 手动加载CUDA库(应用程序未链接到libcuda)
    • 如果库不存在则未安装CUDA驱动程序
  2. 查找库中必要功能的指针
  3. 使用驱动程序API查询有关可用GPU的信息
  4. 我希望这段代码会有所帮助。我在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
    

    干杯

答案 1 :(得分:1)

当然这些人都知道答案:

http://www.ozone3d.net/gpu_caps_viewer

但我只能知道我可以安装CUDA或OpenCL。

我认为有一种方法可以直接使用OpenGL,也许这就是你所说的驱动程序API,但我只能给你这些例子(需要CUDA):

http://www.naic.edu/~phil/hardware/nvidia/doc/src/deviceQuery/deviceQuery.cpp

答案 2 :(得分:1)

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

答案 3 :(得分:0)

我通过静态使用和链接CUDA 6.0 SDK解决了这个问题。它生成的应用程序也适用于没有NVIDIA卡的机器或未安装SDK的机器。在这种情况下,它将表明没有CUDA功能的设备。

CUDA SDK calld 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;
}