Как я могу заставить CMake автоматически определять значение для CUDA_ARCHITECTURES?

#cmake #cuda #nvidia #build-automation #compute-capability

Вопрос:

Более новые версии CMake (3.18 и более поздние версии) «осведомлены» о выборе архитектур CUDA, для которых предназначена компиляция кода CUDA. Целевые объекты имеют CUDA_ARCHITECTURES свойство, которое при задании создает -gencode arch=whatever,code=whatever для вас соответствующие параметры компиляции. Вы даже получите предупреждение, если не установите это значение:

 CMake Error in CMakeLists.txt:
  CUDA_ARCHITECTURES is empty for target "my_cuda_app".
 

по умолчанию это целевое свойство инициализируется CMAKE_CUDA_ARCHITECTURES . Но CMAKE_CUDA_ARCHITECTURES сам он ни к чему не инициализирован (!)

Как мы можем заставить CMake автоматически определять соответствующее значение CUDA_ARCHITECTURES или глобальное CMAKD_CUDA_ARCHITECTURES значение ? То есть использовать архитектуры графических процессоров, установленных в системе?

Ответ №1:

CMake на самом деле предлагает такую возможность автоматического обнаружения, но:

  1. Он недокументирован (и, вероятно, будет переработан в какой-то момент в будущем).
  2. Это часть устаревшего механизма FindCUDA, и он ориентирован на прямое манипулирование CUDA_CMAKE_FLAGS (чего мы не хотим).
  3. Он не «играет хорошо» и скрывает от нас свои внутренние переменные полезной формы.

Тем не менее, с небольшим количеством смазки для локтей, мы можем заставить это работать.

Во-первых, его местоположение: он находится в модуле FindCUDA/select_compute_arch (который в системе Linux будет находиться внутри /path/to/cmake/root/share/cmake-X.YY/Modules/FindCUDA/select_compute_arch.cmake ).

Теперь вот как вы его используете:

 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(TARGET my_target PROPERTY "${CUDA_ARCH_LIST}")
 

Примечания:

  • Когда в вашей системе нет графических процессоров, вы можете получить такой результат, как: 3.5;5.0;5.3;6.0;6.1;7.0;7.5;7.5 PTX .

    Это проблема с CMake, которая не будет решена, так как подмодуль, который мы здесь используем, официально не поддерживается. Поэтому, если вам нужно выполнить компиляцию в системах без графических процессоров, либо избегайте этого вызова, либо проанализируйте свои результаты для записи » PTX».

  • select_compute_arch Подмодуль существует гораздо дольше, но в прошлом вы использовали бы его по-другому и включили бы его до include(FindCUDA) конца .
  • Интересно, LIST(APPEND CMAKE_CUDA_ARCHITECTURES не было бы более уместно, чем SET(CMAKE_CUDA_ARCHITECTURES .
  • Смотрите CMake выпуски 22375 и 19199, чтобы узнать, куда CMake может пойти с этим в будущем. Предостережение: я зарегистрировал эти ошибки…

Комментарии:

1. set_property(TARGET my_target PROPERTY "${CUDA_ARCH_LIST}") (с кавычками) может работать немного лучше, потому что если переменная пуста, это приводит к жесткой синтаксической ошибке.

2. Это не сработало для меня в системе с CMake 3.13, мне пришлось использовать «cuda_select_nvcc_arch_flags(ARCH_FLAGS» Авто») » для этой системы, которая не работает для более поздних версий CMake (например, 3.16). Смотрите мой ответ на охтер.

Ответ №2:

У меня были проблемы с использованием другого решения с системой с CMake 3.13, не уверен, что это такое, но мне пришлось использовать это.

Вероятно, есть лучший способ сделать это.

     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()