7

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

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

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

  • 有这样的开源代码吗?

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

编辑

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

4

4 回答 4

8

不幸的是,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

干杯

于 2012-10-12T07:30:35.163 回答
1

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

于 2012-10-11T08:24:07.963 回答
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

于 2012-10-10T23:59:20.567 回答
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;
}
于 2017-12-11T08:50:42.840 回答