从 cmake 测试是否存在支持 cuda 的 GPU 的最简单方法是什么? [英] Easiest way to test for existence of cuda-capable GPU from cmake?
问题描述
我们有一些安装了 cuda 库的夜间构建机器,但它们确实没有安装支持 cuda 的 GPU.这些机器能够构建支持 cuda 的程序,但不能运行这些程序.
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.
在我们的自动化夜间构建过程中,我们的 cmake 脚本使用 cmake 命令
In our automated nightly build process, our cmake scripts use the cmake command
find_package(CUDA)
判断是否安装了cuda软件.这会在安装了 cuda 软件的平台上设置 cmake 变量 CUDA_FOUND
.这很棒,而且效果很好.当设置了 CUDA_FOUND
时,就可以构建启用 cuda 的程序了.即使机器没有支持 cuda 的 GPU.
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.
但是使用 cuda 的测试程序在非 GPU cuda 机器上自然会失败,导致我们的夜间仪表板看起来脏".所以我希望 cmake 避免在这些机器上运行这些测试.但我仍然想在这些机器上构建 cuda 软件.
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.
在获得肯定的 CUDA_FOUND
结果后,我想测试是否存在实际的 GPU,然后设置一个变量,例如 CUDA_GPU_FOUND
,以反映这一点.
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.
让 cmake 测试是否存在支持 cuda 的 gpu 的最简单方法是什么?
What is the simplest way to get cmake to test for the presence of a cuda-capable gpu?
这需要在三个平台上运行:带有 MSVC 的 Windows、Mac 和 Linux.(这就是我们首先使用 cmake 的原因)
This needs to work on three platforms: Windows with MSVC, Mac, and Linux. (That's why we use cmake in the first place)
关于如何编写程序来测试 GPU 是否存在的答案中有一些好看的建议.仍然缺少的是让 CMake 在配置时编译和运行该程序的方法.我怀疑 CMake 中的 TRY_RUN
命令在这里很关键,但不幸的是该命令是 几乎没有记录,我不知道如何让它工作.问题的这个 CMake 部分可能是一个更困难的问题.也许我应该把这个作为两个单独的问题来问......
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:
- 检测是否存在支持 cuda 的 GPU 的程序.
- 用于在配置时编译、运行和解释该程序结果的 CMake 代码.
对于第 1 部分,gpu 嗅探程序,我从 fabrizioM 提供的答案开始,因为它非常紧凑.我很快发现我需要在未知的答案中找到许多细节才能使其正常工作.我最终得到的是以下 C 源文件,我将其命名为 has_cuda_gpu.c
:
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
", 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 */
}
请注意,在找到支持 cuda 的 GPU 的情况下,返回码为零.这是因为在我的一台 has-cuda-but-no-GPU 机器上,该程序生成一个运行时错误,退出代码非零.因此,任何非零退出代码都被解释为cuda 在这台机器上不起作用".
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".
您可能会问为什么我不在非 GPU 机器上使用 cuda 仿真模式.这是因为仿真模式是错误的.我只想调试我的代码,并解决 cuda GPU 代码中的错误.我没时间调试模拟器.
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.
问题的第二部分是使用这个测试程序的cmake代码.经过一番挣扎,我想通了.以下块是较大的 CMakeLists.txt
文件的一部分:
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)
这会在 cmake 中设置一个 CUDA_HAVE_GPU
布尔变量,该变量随后可用于触发条件操作.
This sets a CUDA_HAVE_GPU
boolean variable in cmake that can subsequently be used to trigger conditional operations.
我花了很长时间才弄清楚包含和链接参数需要放在 CMAKE_FLAGS 节中,以及语法应该是什么.try_run 文档很简单,但在 try_compile 文档中有更多信息,这是一个密切相关的命令.在让它工作之前,我仍然需要在网上搜索 try_compile 和 try_run 的示例.
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.
另一个棘手但重要的细节是 try_run
的第三个参数,即bindir".您可能应该始终将其设置为 ${CMAKE_BINARY_DIR}
.特别是,如果您位于项目的子目录中,请不要将其设置为 ${CMAKE_CURRENT_BINARY_DIR}
.CMake 期望在 bindir 中找到 CMakeFiles/CMakeTmp
子目录,如果该目录不存在,则会出现错误.只需使用 ${CMAKE_BINARY_DIR}
,这是这些子目录似乎自然存在的一个位置.
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屋!