[Last updated on Feb 26, 2020]
The latest cmake 3.17 has just started to officially support a new module FindCUDAToolkit where NVML library is conveniently referenced by the target CUDA::nvml. With this new feature this article is now deprecated.
Nvidia Management Library (NVML) is a powerful API to get and set GPU states. Currently there is a lack of official CMake support. The first couple of google search results point to a script on github, which unfortunately is only partially correct and does not work on Windows. Here we provide a working solution, tested on Scientific Linux 6 and Windows 10, with CUDA 9.1 and CMake 3.11.
The NVML API is spread across several locations:
- Linux
- Header: ${CUDA_INCLUDE_DIRS}/nvml.h
- Shared library: ${CUDA_TOOLKIT_ROOT_DIR}/lib64/stubs/libnvidia-ml.so
- Windows
- Header: ${CUDA_INCLUDE_DIRS}/nvml.h
- Shared library: C:/Program Files/NVIDIA Corporation/NVSMI/nvml.dll
- Import library: ${CUDA_TOOLKIT_ROOT_DIR}/lib/x64/nvml.lib
It is critical to note that, on Windows a dynamic library (.dll) is accompanied by an import library (.lib), which is different from a static library (also .lib). In CMake the target binary should link to the import library (.lib) directly instead of the .dll file. With that, the correct FindNVML.cmake script is shown in listing 1.
Listing 1
# FindNVML.cmake if(${CUDA_VERSION_STRING} VERSION_LESS "9.1") string(CONCAT ERROR_MSG "--> ARCHER: Current CUDA version " ${CUDA_VERSION_STRING} " is too old. Must upgrade it to 9.1 or newer.") message(FATAL_ERROR ${ERROR_MSG}) endif() # windows, including both 32-bit and 64-bit if(WIN32) set(NVML_NAMES nvml) set(NVML_LIB_DIR "${CUDA_TOOLKIT_ROOT_DIR}/lib/x64") set(NVML_INCLUDE_DIR ${CUDA_INCLUDE_DIRS}) # .lib import library full path find_file(NVML_LIB_PATH NO_DEFAULT_PATH NAMES nvml.lib PATHS ${NVML_LIB_DIR}) # .dll full path find_file(NVML_DLL_PATH NO_DEFAULT_PATH NAMES nvml.dll PATHS "C:/Program Files/NVIDIA Corporation/NVSMI") # linux elseif(UNIX AND NOT APPLE) set(NVML_NAMES nvidia-ml) set(NVML_LIB_DIR "${CUDA_TOOLKIT_ROOT_DIR}/lib64/stubs") set(NVML_INCLUDE_DIR ${CUDA_INCLUDE_DIRS}) find_library(NVML_LIB_PATH NO_DEFAULT_PATH NAMES ${NVML_NAMES} PATHS ${NVML_LIB_DIR}) else() message(FATAL_ERROR "Unsupported platform.") endif() find_path(NVML_INCLUDE_PATH NO_DEFAULT_PATH NAMES nvml.h PATHS ${NVML_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(NVML DEFAULT_MSG NVML_LIB_PATH NVML_INCLUDE_PATH)
Once find_package(NVML) is called in user CMake code, two cache variables are generated: NVML_LIB_PATH and NVML_INCLUDE_PATH. For Windows, there is an additional NVML_DLL_PATH.