Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cuda: CMake add CUDA first class language support #23021

Merged
merged 2 commits into from Dec 26, 2023

Conversation

cudawarped
Copy link
Contributor

@cudawarped cudawarped commented Dec 23, 2022

This PR adds CUDA first class language support which has been avaliable since CMake 3.8. Currently OpenCV uses the depreciated (since CMake 3.10) FindCUDA module.

This new feature is added automatically when OpenCV is built against CMake >= 3.18 (when the FindCUDAToolkit results variable CUDAToolkit_LIBRARY_ROOT was added). It can be disabled by passing -DENABLE_CUDA_FIRST_CLASS_LANGUAGE=OFF to CMake.

All projects which use OpenCV targets built with -DENABLE_CUDA_FIRST_CLASS_LANGUAGE=ON need to use CMake >=3.18 due to the new imported targets provided by FindCUDAToolkit.

Fixes #23422, fixes #23659, fixes #24034, fixes #24177, fixes #24195, fixes opencv/opencv_contrib#3143, fixes opencv/opencv_contrib#3414

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake
force_builders=Custom
buildworker:Custom=linux-1
docker_image:Custom=ubuntu-cuda:16.04

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution!

CMakeLists.txt Outdated Show resolved Hide resolved
@@ -1,3 +1,50 @@
if(ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 375 changes in this file which size is 577 lines on 4.x branch (more that 50%).

To avoid mess and/or breaking of existed legacy code my proposal is creating a copy of this file, cleanup dead code, and specify code for the new CUDA support.


if(NOT CUDA_FOUND)
find_host_package(CUDA ${OpenCV_CUDA_VERSION} EXACT REQUIRED)
set(ENABLE_CUDA_FIRST_CLASS_LANGUAGE "@ENABLE_CUDA_FIRST_CLASS_LANGUAGE@")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same issue: 70 changes for 48 lines.

Please create dedicated file.

CMakeLists.txt Show resolved Hide resolved
@cudawarped cudawarped force-pushed the add_cuda_first_class_support branch 3 times, most recently from c978566 to 07e9f8d Compare February 28, 2023 10:56
@cudawarped
Copy link
Contributor Author

Changes applied and tested on both Windows and Ubuntu (dynamic and static) although I am sure I haven't tested every conceivable combination of build parameters which might fail.

@cudawarped cudawarped changed the title CMake add CUDA first class language support cuda: CMake add CUDA first class language support Apr 5, 2023
@asmorkalov asmorkalov modified the milestones: 4.8.0, 4.9.0 May 15, 2023
@cudawarped
Copy link
Contributor Author

@asmorkalov what does this PR need for this to be part of 4.9.0?

@cudawarped
Copy link
Contributor Author

cudawarped commented Jul 11, 2023

@alalek, @asmorkalov I have just noticed that in the latest version of CMake (3.27) FindCUDA will be removed unless the below policy flag is used.

Changed in version 3.27: This module is available only if policy CMP0146 is not set to NEW. Port projects to CMake's first-class CUDA language support.

Thats fine as OpenCV has a fallback version but this will probably mean that bugs like this one #23280 won't be fixed in future.

What needs to be changed for this to be merged?

cmake/OpenCVDetectCUDALanguage.cmake Outdated Show resolved Hide resolved
cmake/OpenCVDetectCUDALanguage.cmake Outdated Show resolved Hide resolved
cmake/OpenCVDetectCUDALanguage.cmake Outdated Show resolved Hide resolved
cmake/OpenCVDetectCUDA.cmake Outdated Show resolved Hide resolved
Copy link
Contributor

@mshabunin mshabunin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested build procedure on Linux with CUDA 12 and 11. Overall looks good to me. One question with keeping CUDA location guessing need to be discussed.

@danielnilsson9
Copy link

I'm trying to apply these patches to 4.8.1 to build a conan package. I hade to make some minor modification to get it to apply but I think I did it correctly but I guess maybe not.

I'm having problems with the the auto detection of CUDA architectures during configure, is it supposed to work? The variable ${CUDA_NVCC_EXECUTABLE} does not seem to be defined.

buildlog.txt

@cudawarped
Copy link
Contributor Author

cudawarped commented Nov 30, 2023

I'm having problems with the the auto detection of CUDA architectures during configure, is it supposed to work? The variable ${CUDA_NVCC_EXECUTABLE} does not seem to be defined.

@danielnilsson9 sorry I've just notice that I broke that when I unified everything into one utils file last month. I've pushed a fix which I am still testing but feel free to try it in the meantime.

@cudawarped
Copy link
Contributor Author

One question with keeping CUDA location guessing need to be discussed.

@mshabunin Is there any harm in including it with the below status reports?

> -- CUDA not detected, make sure you have performed the mandatory Post-installation actions described in the CUDA installation guide.
> -- Falling back to checking for the CUDA compiler in its default location (/usr/local/cuda)

CI has passed but I need to update some of the status messages for Linux am I OK to do so?

@mshabunin
Copy link
Contributor

I think it's OK to include such messages. I'd also add hints regarding adding nvcc location to the PATH or setting CUDA_PATH env variable.

@danielnilsson9
Copy link

danielnilsson9 commented Nov 30, 2023

@cudawarped Thank you for the quick fix! I got a bit further now, I can build if my host compiler is in PATH but that should not be required I think, since CMake discoveres the compiler. It think it needs to be passed as argument to nvcc (-ccbin).

buildlog2.txt


if(OPENCV_CUDA_DETECTION_NVCC_FLAGS MATCHES "-ccbin")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code needs to be kept to auto set host compiler

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added back in, in the latest commit, can you take a look if you have chance?

@cudawarped
Copy link
Contributor Author

@r2d3 Do you have any more comments regarding this PR?

@danielnilsson4
Copy link

danielnilsson4 commented Dec 13, 2023

I'm back at this again but this time trying to build opencv with CUDA (using cmake/ninja) and clang 16 on ubuntu 22.04 LTS.
I'm having multiple issues.

I have set
CMAKE_CUDA_HOST_COMPILER to "clang++"

My conan packaged cuda toolkit/bin is in path and env CUDA_PATH point to root of toolkit.

For some reason

include(CheckLanguage)
check_language(CUDA)

fails to discover cuda compiler but if I uncomment these two lines and do enable_language(CUDA) directly instead it works, I need to investigate that further. EDIT: You must also set CMAKE_CUDA_COMPILER when setting CMAKE_CUDA_HOST_COMPILER for check language to work (https://gitlab.kitware.com/cmake/cmake/-/issues/25093#note_1392691).

When I get past that if fails at ocv_filter_available_architecture.
CMAKE_CUDA_HOST_COMPILER is not taken into consideration, clang++ not passed using ccbin but hardcoded to pass host compiler bin dir instead and nvcc then defaults to gcc.

If I pass "-ccbin clang++" using OPENCV_CUDA_DETECTION_NVCC_FLAGS it will fail anyway since ccbin is then passed twice.
After fixing that the build is successful.

I will try building from source from your branch tomorrow and post logs if you want. Currently building using an older patch where your latest changes have not ben added..

@cudawarped
Copy link
Contributor Author

cudawarped commented Dec 14, 2023

I have set CMAKE_CUDA_HOST_COMPILER to "clang++"

My conan packaged cuda toolkit/bin is in path and env CUDA_PATH point to root of toolkit.

For some reason

include(CheckLanguage)
check_language(CUDA)

I'm new to clang so forgive me if I am missing something.

How are you instructing cmake to use clang as the host compiler?

If I set -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=clang++ then CMAKE_CUDA_HOST_COMPILER is not required because CMake picks up clang by itself finds CUDA successfully and also does not need to add the location of the nvcc compiler when manually compiling the .cu files in ocv_filter_available_architecture?

My conan packaged cuda toolkit/bin is in path and env CUDA_PATH point to root of toolkit.

Does this work if you set CUDA_PATH to the root directory, i.e. /usr/local/cuda?

@danielnilsson4
Copy link

I have set CMAKE_CUDA_HOST_COMPILER to "clang++"
My conan packaged cuda toolkit/bin is in path and env CUDA_PATH point to root of toolkit.
For some reason

include(CheckLanguage)
check_language(CUDA)

I'm new to clang so forgive me if I am missing something.

How are you instructing cmake to use clang as the host compiler?

No, not really, I don't have gcc installed at all on my system (except libstdc++), only clang and it is set as default compiler on system so CMake finds it automatically (linked in /usr/bin/c++, /usr/bin/cc and ENV $CC and $CXX are set to point to clang).

If you have gcc installed and on your system nvcc will automatically use if you do not pass -ccbin clang++, so that may be why it appears to work for you even though clang was not used when the architecture tests where done and they only worked because GCC was present on system.

From https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html:
"On all platforms, the default host compiler executable (gcc and g++ on Linux and cl.exe on Windows) found in the current execution search path will be used, unless specified otherwise with appropriate options"

If I set -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=clang++ then CMAKE_CUDA_HOST_COMPILER is not required because CMake picks up clang by itself finds CUDA successfully and also does not need to add the location of the nvcc compiler when manually compiling the .cu files in ocv_filter_available_architecture?

My conan packaged cuda toolkit/bin is in path and env CUDA_PATH point to root of toolkit.

Does this work if you set CUDA_PATH to the root directory, i.e. /usr/local/cuda?

I have not tried that yet, will do.

@cudawarped
Copy link
Contributor Author

cudawarped commented Dec 14, 2023

No, not really, I don't have gcc installed at all on my system (except libstdc++), only clang and it is set as default compiler on system so CMake finds it automatically (linked in /usr/bin/c++, /usr/bin/cc and ENV $CC and $CXX are set to point to clang).

My mistake.

EDIT: You must also set CMAKE_CUDA_COMPILER when setting CMAKE_CUDA_HOST_COMPILER for check language to work (https://gitlab.kitware.com/cmake/cmake/-/issues/25093#note_1392691).

Thank you for the link on my system the following compilation flags work when gcc is not found

-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/clang++ -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc

@danielnilsson4 I think that this configuration should be passed by the user if they want to use clang and we can hint at this when CUDA is not found, e.g.

-- Looking for a CUDA compiler
-- Looking for a CUDA compiler - NOTFOUND
-- Looking for a CUDA host compiler - /usr/bin/clang++
-- CUDA: Not detected, make sure you have performed the mandatory Post-installation actions described in the CUDA installation guide.
   For stand alone installations you can set the CUDA_PATH environmental or CMake variable. e.g. export CUDA_PATH=/usr/local/cuda-XX.X or -DCUDA_PATH=/usr/local/cuda-XX.X.
-- CUDA: Falling back to searching for the CUDA compiler in its default location (/usr/local/cuda)
-- Looking for a CUDA compiler
-- Looking for a CUDA compiler - NOTFOUND
-- Looking for a CUDA host compiler - /usr/bin/clang++
CMake Warning at CMakeLists.txt:707 (message):
  CUDA: Not detected! If you are not using the default host compiler (g++)
  then you need to specify both CMAKE_CUDA_HOST_COMPILER and
  CMAKE_CUDA_COMPILER.  e.g.  -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/clang++
  -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc.

What do you think?

@danielnilsson4
Copy link

What do you think?

Looks good, I think that is the correct approach to take.

I looked at your latest code, seems like you had already fixed the issue I had in ocv_filter_available_architecture, I had not adjusted my patch with yours, sorry about that. I think it is all ok then,

I had:
set(NVCC_OPTION "-ccbin=${HOST_COMPILER_BIN_DIR};gencode;arch=compute_${target_arch_short},code=sm_${target_arch_short}")

Where you must have removed -ccbin=${HOST_COMPILER_BIN_DIR} at some point which I had missed.

@asmorkalov
Copy link
Contributor

Rebased and fixed conflicts with #24744

@asmorkalov
Copy link
Contributor

@cudawarped I disabled ENABLE_CUDA_FIRST_CLASS_LANGUAGE for now to presume existing behaviour for old users and not to break existing CI. CUDA is not detected with ENABLE_CUDA_FIRST_CLASS_LANGUAGE=ON if, nvcc is not in PATH. Let's release 4.9.0 with the experimental support and enable it by default for the next release, when we get feedback.

@asmorkalov
Copy link
Contributor

Tested manually with:

  • Ubuntu 18.04 + CUDA 11.8 both cases.
  • Jetson ORIN + CUDA 11.4 old branch only.
  • Windows 10 + CUDA 12.3 both branches.

@asmorkalov asmorkalov merged commit e80b794 into opencv:4.x Dec 26, 2023
26 checks passed
@asmorkalov asmorkalov mentioned this pull request Jan 19, 2024
macro(ocv_set_cuda_detection_nvcc_flags cuda_host_compiler_var)
if(OPENCV_CUDA_DETECTION_NVCC_FLAGS MATCHES "-ccbin")
# already specified by user
elseif(${cuda_host_compiler_var} AND EXISTS "${${cuda_host_compiler_var}}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgraded our conan packaged solution to OpenCV 4.9.0. This EXISTS check requires that the full path to clang++ is specified, it's not possible to just set CMAKE_CUDA_HOST_COMPILER=clang++. A bit annoying but not a huge deal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we might call find_program here? Or somewhere earlier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment