Reputation: 132340
Newer versions of CMake (3.18 and later), are "aware" of the choice of CUDA architectures which compilation of CUDA code targets. Targets have a CUDA_ARCHITECTURES
property, which, when set, generates the appropriate -gencode arch=whatever,code=whatever
compilation options for you. You will even get a warning if you don't set this value:
CMake Error in CMakeLists.txt:
CUDA_ARCHITECTURES is empty for target "my_cuda_app".
by default, this target property is initialized to CMAKE_CUDA_ARCHITECTURES
. But CMAKE_CUDA_ARCHITECTURES
itself is not initialized to anything (!)
How can we have CMake auto-detect an appropriate value for CUDA_ARCHITECTURES
or the global CMAKD_CUDA_ARCHITECTURES
? That is, use the architectures of GPUs installed on the system?
Upvotes: 7
Views: 22773
Reputation: 10916
I typically do this on the cmake
command line, e.g.:
$ export CUDACXX="/usr/local/cuda/bin/nvcc"
$ cmake -DCMAKE_CUDA_ARCHITECTURES=native -DCMAKE_BUILD_TYPE=Release ..
Upvotes: 4
Reputation: 132340
In the upcoming CMake 3.24, you will be able to write:
set_property(TARGET tgt PROPERTY CUDA_ARCHITECTURES native)
and this will build target tgt
for the (concrete) CUDA architectures of GPUs available on your system at configuration time.
With newer versions of CUDA (11.5 and later), the will pass native
on to nvcc and other executables; with older versions, it will auto-detect which architectures are the 'native' ones.
Caveat: This does not actually give you the list of architectures (e.g. to iterate in your CMake code.)
Upvotes: 12
Reputation: 16320
I had problems using the other solution with a system with CMake 3.13, not sure what it is but I had to use this.
There is probably a better way to do this.
if(${CMAKE_VERSION} VERSION_LESS_EQUAL "3.13.4")
cuda_select_nvcc_arch_flags(ARCH_FLAGS "Auto") # optional argument for arch to add
message("ARCH_FLAGS = ${ARCH_FLAGS}")
string(REPLACE "-gencode;" "--generate-code=" ARCH_FLAGS "${ARCH_FLAGS}")
string(APPEND CMAKE_CUDA_FLAGS "${ARCH_FLAGS}")
else()
include(FindCUDA/select_compute_arch)
CUDA_DETECT_INSTALLED_GPUS(INSTALLED_GPU_CCS_1)
string(STRIP "${INSTALLED_GPU_CCS_1}" INSTALLED_GPU_CCS_2)
string(REPLACE " " ";" INSTALLED_GPU_CCS_3 "${INSTALLED_GPU_CCS_2}")
string(REPLACE "." "" CUDA_ARCH_LIST "${INSTALLED_GPU_CCS_3}")
SET(CMAKE_CUDA_ARCHITECTURES ${CUDA_ARCH_LIST})
set_property(GLOBAL PROPERTY CUDA_ARCHITECTURES "${CUDA_ARCH_LIST}")
endif()
Upvotes: 4
Reputation: 132340
CMake actually offers such autodetection capability, but:
CUDA_CMAKE_FLAGS
(which isnt what we want).Still, with a little elbow grease, we can make it work.
First, its location: It's in a module, FindCUDA/select_compute_arch
(which, on a Linux system, will be located in /path/to/cmake/root/share/cmake-X.YY/Modules/FindCUDA/select_compute_arch.cmake
).
Now here's how you use it:
include(FindCUDA/select_compute_arch)
CUDA_DETECT_INSTALLED_GPUS(INSTALLED_GPU_CCS_1)
string(STRIP "${INSTALLED_GPU_CCS_1}" INSTALLED_GPU_CCS_2)
string(REPLACE " " ";" INSTALLED_GPU_CCS_3 "${INSTALLED_GPU_CCS_2}")
string(REPLACE "." "" CUDA_ARCH_LIST "${INSTALLED_GPU_CCS_3}")
SET(CMAKE_CUDA_ARCHITECTURES ${CUDA_ARCH_LIST})
If you only want this for a single target, you would replace the last line with:
set_property(TARGET my_target PROPERTY "${CUDA_ARCH_LIST}")
Notes:
When there are no GPUs on your system you may get a result such as: 3.5;5.0;5.3;6.0;6.1;7.0;7.5;7.5+PTX
.
This is an issue with CMake which will not be resolved, since the submodule we're using here is not officially supported. So, if you need to compile on systems with no GPUs, either avoid this call or parse your results for the "+PTX" entry.
The select_compute_arch
submodule has existed for much longer, but in the past you would use it differently, and would include it through include(FindCUDA)
.
I wonder if LIST(APPEND CMAKE_CUDA_ARCHITECTURES
might not be more appropriate than SET(CMAKE_CUDA_ARCHITECTURES
.
See CMake issues 22375 and 19199 for where CMake might go with this in the future. Caveat: I filed those bugs...
Upvotes: 7