最简单的方法来测试来自cmake的cuda功能的GPU的存在? [英] Easiest way to test for existence of cuda-capable GPU from cmake?

查看:2558
本文介绍了最简单的方法来测试来自cmake的cuda功能的GPU的存在?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一些夜间构建机器,它们安装了 cuda库,但它们没有安装cuda功能的GPU。这些机器能够构建支持cuda的程序,但是它们不能运行这些程序。



在我们的自动化夜间构建过程中,我们的cmake脚本使用cmake命令



find_package(CUDA)



安装cuda软件。这会在安装了cuda软件的平台上设置cmake变量 CUDA_FOUND 。这是伟大的,它的作品完美。当设置 CUDA_FOUND 时,可以构建支持cuda的程序。即使当机器没有cuda功能的GPU。



但是cuda使用测试程序自然失败在非GPU CUDA机器,导致我们的夜间仪表板看起来脏 。所以我想要cmake避免在这样的机器上运行这些测试。但我仍然想在这些机器上构建cuda软件。



在得到一个积极的 CUDA_FOUND 结果后,喜欢测试实际GPU的存在,然后设置一个变量,例如 CUDA_GPU_FOUND ,以反映这一点。



这需要在三个平台上工作:Windows与MSVC,Mac ,和Linux。 (这就是为什么我们首先使用cmake)



编辑:在答案中有几个很好的建议如何写一个程序来测试GPU的存在。仍然缺少的是使CMake在配置时编译和运行此程序的方法。我怀疑在CMake中的 TRY_RUN 命令将是至关重要的,但不幸的是,该命令是几乎无证件,我不知道如何使它工作。这个问题的CMake部分可能是一个更困难的问题。也许我应该问这是两个单独的问题...

解决方案

这个问题的答案包括两部分: p>


  1. 用于检测是否存在支持cuda的GPU的程序。

  2. CMake代码编译,运行,并在配置时解释程序的结果。

对于第1部分,gpu嗅探程序,由fabrizioM因为它是如此紧凑。我很快发现,我需要许多细节找到未知的答案,使其工作得很好。我最后得到的是以下C源文件,我命名为 has_cuda_gpu.c

  #include< stdio.h> 
#include< cuda_runtime.h>

int main(){
int deviceCount,device;
int gpuDeviceCount = 0;
struct cudaDeviceProp properties;
cudaError_t cudaResultCode = cudaGetDeviceCount(& deviceCount);
if(cudaResultCode!= cudaSuccess)
deviceCount = 0;
/ *没有GPU的机器仍然可以为(device = 0; device< deviceCount; ++ device){
cudaGetDeviceProperties(& properties,device))报告一个仿真设备* /
;
if(properties.major!= 9999)/ * 9999只表示模拟* /
++ gpuDeviceCount;
}
printf(%d GPU CUDA device(s)found \\\
,gpuDeviceCount);

/ *不只是返回gpus的数量,因为其他运行时cuda
错误也可以产生非零返回值* /
if(gpuDeviceCount> 0)
return 0; / * success * /
else
return 1; / * failure * /
}

请注意,找到启用CUDA的GPU。这是因为在我的一个没有GPU的机器上,这个程序产生一个非零退出代码的运行时错误。所以任何非零退出代码都被解释为cuda在这台机器上不工作。



你可能会问为什么我不使用cuda emulation模式, GPU机器。这是因为仿真模式是错误的。我只想调试我的代码,并解决cuda GPU代码中的错误。我没有时间去调试仿真器。



问题的第二部分是使用这个测试程序的cmake代码。经过一番斗争,我想出来了。以下块是更大的 CMakeLists.txt 文件的一部分:

  find_package(CUDA)
if(CUDA_FOUND)
try_run(RUN_RESULT_VAR COMPILE_RESULT_VAR
$ {CMAKE_BINARY_DIR}
$ {CMAKE_CURRENT_SOURCE_DIR} /has_cuda_gpu.c
CMAKE_FLAGS
- DINCLUDE_DIRECTORIES:STRING = $ {CUDA_TOOLKIT_INCLUDE}
-DLINK_LIBRARIES:STRING = $ {CUDA_CUDART_LIBRARY}
COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR
RUN_OUTPUT_VARIABLE RUN_OUTPUT_VAR)
消息($ {RUN_OUTPUT_VAR}找到的GPU
#COMPILE_RESULT_VAR在编译成功时为TRUE
#找到GPU时,RUN_RESULT_VAR为零
if(COMPILE_RESULT_VAR AND NOT RUN_RESULT_VAR)
set(CUDA_HAVE_GPU TRUE CACHE BOOL支持CUDA的GPU)
else()
set(CUDA_HAVE_GPU FALSE CACHE BOOL是否支持CUDA的GPU)
endif()
endif(CUDA_FOUND)

这会在cmake中设置一个 CUDA_HAVE_GPU 布尔变量可以随后用于触发条件操作。



我花了很长时间才发现include和链接参数需要在CMAKE_FLAGS节中,语法应该是。 try_run文档非常轻,但 try_compile文档中有更多信息, a>,这是一个密切相关的命令。



另一个棘手但重要的细节是的第三个参数, try_run ,bindir。你应该总是设置为 $ {CMAKE_BINARY_DIR} 。特别是,如果您位于项目的子目录中,请不要将其设置为 $ {CMAKE_CURRENT_BINARY_DIR} 。 CMake希望在bindir中找到子目录 CMakeFiles / CMakeTmp ,如果该目录不存在,则会抛出错误。只需使用 $ {CMAKE_BINARY_DIR} ,这是这些子目录似乎自然存在的位置。


We have some nightly build machines that have the cuda libraries installed, but which do not have a cuda-capable GPU installed. These machines are capable of building cuda-enabled programs, but they are not capable of running these programs.

In our automated nightly build process, our cmake scripts use the cmake command

find_package(CUDA)

to determine whether the cuda software is installed. This sets the cmake variable CUDA_FOUND on platforms that have cuda software installed. This is great and it works perfectly. When CUDA_FOUND is set, it is OK to build cuda-enabled programs. Even when the machine has no cuda-capable GPU.

But cuda-using test programs naturally fail on the non-GPU cuda machines, causing our nightly dashboards look "dirty". So I want cmake to avoid running those tests on such machines. But I still want to build the cuda software on those machines.

After getting a positive CUDA_FOUND result, I would like to test for the presence of an actual GPU, and then set a variable, say CUDA_GPU_FOUND, to reflect this.

What is the simplest way to get cmake to test for the presence of a cuda-capable gpu?

This needs to work on three platforms: Windows with MSVC, Mac, and Linux. (That's why we use cmake in the first place)

EDIT: There are a couple of good looking suggestions in the answers for how write a program to test for the presence of a GPU. What is still missing is the means of getting CMake to compile and run this program at configuration time. I suspect that the TRY_RUN command in CMake will be critical here, but unfortunately that command is nearly undocumented, and I cannot figure out how to make it work. This CMake part of the problem might be a much more difficult question. Perhaps I should have asked this as two separate questions...

解决方案

The answer to this question consists of two parts:

  1. A program to detect the presence of a cuda-capable GPU.
  2. CMake code to compile, run, and interpret the result of that program at configuration time.

For part 1, the gpu sniffing program, I started with the answer provided by fabrizioM because it is so compact. I quickly discovered that I needed many of the details found in unknown's answer to get it to work well. What I ended up with is the following C source file, which I named has_cuda_gpu.c:

#include <stdio.h>
#include <cuda_runtime.h>

int main() {
    int deviceCount, device;
    int gpuDeviceCount = 0;
    struct cudaDeviceProp properties;
    cudaError_t cudaResultCode = cudaGetDeviceCount(&deviceCount);
    if (cudaResultCode != cudaSuccess) 
        deviceCount = 0;
    /* machines with no GPUs can still report one emulation device */
    for (device = 0; device < deviceCount; ++device) {
        cudaGetDeviceProperties(&properties, device);
        if (properties.major != 9999) /* 9999 means emulation only */
            ++gpuDeviceCount;
    }
    printf("%d GPU CUDA device(s) found\n", gpuDeviceCount);

    /* don't just return the number of gpus, because other runtime cuda
       errors can also yield non-zero return values */
    if (gpuDeviceCount > 0)
        return 0; /* success */
    else
        return 1; /* failure */
}

Notice that the return code is zero in the case where a cuda-enabled GPU is found. This is because on one of my has-cuda-but-no-GPU machines, this program generates a runtime error with non-zero exit code. So any non-zero exit code is interpreted as "cuda does not work on this machine".

You might ask why I don't use cuda emulation mode on non-GPU machines. It is because emulation mode is buggy. I only want to debug my code, and work around bugs in cuda GPU code. I don't have time to debug the emulator.

The second part of the problem is the cmake code to use this test program. After some struggle, I have figured it out. The following block is part of a larger CMakeLists.txt file:

find_package(CUDA)
if(CUDA_FOUND)
    try_run(RUN_RESULT_VAR COMPILE_RESULT_VAR
        ${CMAKE_BINARY_DIR} 
        ${CMAKE_CURRENT_SOURCE_DIR}/has_cuda_gpu.c
        CMAKE_FLAGS 
            -DINCLUDE_DIRECTORIES:STRING=${CUDA_TOOLKIT_INCLUDE}
            -DLINK_LIBRARIES:STRING=${CUDA_CUDART_LIBRARY}
        COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR
        RUN_OUTPUT_VARIABLE RUN_OUTPUT_VAR)
    message("${RUN_OUTPUT_VAR}") # Display number of GPUs found
    # COMPILE_RESULT_VAR is TRUE when compile succeeds
    # RUN_RESULT_VAR is zero when a GPU is found
    if(COMPILE_RESULT_VAR AND NOT RUN_RESULT_VAR)
        set(CUDA_HAVE_GPU TRUE CACHE BOOL "Whether CUDA-capable GPU is present")
    else()
        set(CUDA_HAVE_GPU FALSE CACHE BOOL "Whether CUDA-capable GPU is present")
    endif()
endif(CUDA_FOUND)

This sets a CUDA_HAVE_GPU boolean variable in cmake that can subsequently be used to trigger conditional operations.

It took me a long time to figure out that the include and link parameters need to go in the CMAKE_FLAGS stanza, and what the syntax should be. The try_run documentation is very light, but there is more information in the try_compile documentation, which is a closely related command. I still needed to scour the web for examples of try_compile and try_run before getting this to work.

Another tricky but important detail is the third argument to try_run, the "bindir". You should probably always set this to ${CMAKE_BINARY_DIR}. In particular, do not set it to ${CMAKE_CURRENT_BINARY_DIR} if you are in a subdirectory of your project. CMake expects to find the subdirectory CMakeFiles/CMakeTmp within bindir, and spews errors if that directory does not exist. Just use ${CMAKE_BINARY_DIR}, which is one location where those subdirectories seem to naturally reside.

这篇关于最简单的方法来测试来自cmake的cuda功能的GPU的存在?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆