Fix mdp label generation
[gromacs/AngularHB.git] / cmake / gmxManageGPU.cmake
blobfe1aa0ce9ba7841621f08e50821f5c1023a2a7c8
2 # This file is part of the GROMACS molecular simulation package.
4 # Copyright (c) 2012,2013,2014,2015,2016, by the GROMACS development team, led by
5 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 # and including many others, as listed in the AUTHORS file in the
7 # top-level source directory and at http://www.gromacs.org.
9 # GROMACS is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public License
11 # as published by the Free Software Foundation; either version 2.1
12 # of the License, or (at your option) any later version.
14 # GROMACS is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with GROMACS; if not, see
21 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24 # If you want to redistribute modifications to GROMACS, please
25 # consider that scientific software is very special. Version
26 # control is crucial - bugs must be traceable. We will be happy to
27 # consider code for inclusion in the official distribution, but
28 # derived work must not be called official GROMACS. Details are found
29 # in the README & COPYING files - if they are missing, get the
30 # official version at http://www.gromacs.org.
32 # To help us fund GROMACS development, we humbly ask that you cite
33 # the research papers on the package. Check out http://www.gromacs.org.
35 # If the user did not set GMX_GPU we'll consider this option to be
36 # in "auto" mode meaning that we will:
37 # - search for CUDA and set GMX_GPU=ON we find it
38 # - check whether GPUs are present
39 # - if CUDA is not found but GPUs were detected issue a warning
40 if (NOT DEFINED GMX_GPU)
41     set(GMX_GPU_AUTO TRUE CACHE INTERNAL "GPU acceleration will be selected automatically")
42 endif()
43 option(GMX_GPU "Enable GPU acceleration" OFF)
45 if(GMX_GPU AND GMX_DOUBLE)
46     message(FATAL_ERROR "GPU acceleration is not available in double precision!")
47 endif()
48 if(GMX_GPU_AUTO AND GMX_DOUBLE)
49     message(WARNING "GPU acceleration is not available in double precision, disabled!")
50     set_property(CACHE GMX_GPU PROPERTY VALUE OFF)
51     set_property(CACHE GMX_GPU_AUTO PROPERTY VALUE OFF)
52 endif()
54 # detect GPUs in the build host machine
55 if ((GMX_GPU OR GMX_GPU_AUTO) AND NOT GMX_GPU_DETECTION_DONE)
56     include(gmxDetectGpu)
57     gmx_detect_gpu()
58 endif()
60 # CMake 3.0-3.1 has a bug in the following case, which breaks
61 # configuration on at least BlueGene/Q. Fixed in 3.1.1
62 if ((NOT CMAKE_VERSION VERSION_LESS "3.0.0") AND
63     (CMAKE_VERSION VERSION_LESS "3.1.1") AND
64         (CMAKE_CROSSCOMPILING AND NOT CMAKE_SYSTEM_PROCESSOR))
65     message(STATUS "Cannot search for CUDA because the CMake find package has a bug. Set a valid CMAKE_SYSTEM_PROCESSOR if you need to detect CUDA")
66 else()
67     set(CAN_RUN_CUDA_FIND_PACKAGE 1)
68 endif()
70 # We need to call find_package even when we've already done the detection/setup
71 if(GMX_GPU OR GMX_GPU_AUTO AND CAN_RUN_CUDA_FIND_PACKAGE)
72     if(NOT GMX_GPU AND NOT GMX_DETECT_GPU_AVAILABLE)
73         # Stay quiet when detection has occured and found no GPU.
74         # Noise is acceptable when there is a GPU or the user required one.
75         set(FIND_CUDA_QUIETLY QUIET)
76     endif()
77     find_package(CUDA ${REQUIRED_CUDA_VERSION} ${FIND_CUDA_QUIETLY})
79     # The IBM xlc compiler chokes if we use both altivec and Cuda. Solve
80     # this by not propagating the flags in this case, but add -O3
81     # to make sure we don't turn off optimization.
82     if(CMAKE_CXX_COMPILER_ID MATCHES "XL")
83         set(CUDA_PROPAGATE_HOST_FLAGS OFF)
84         list(APPEND CUDA_NVCC_FLAGS "-O3")
85     endif()
87     # Cmake 2.8.12 (and CMake 3.0) introduced a new bug where the cuda
88     # library dir is added twice as an rpath on APPLE, which in turn causes
89     # the install_name_tool to wreck the binaries when it tries to remove this
90     # path. Since this is set inside the cuda module, we remove the extra rpath
91     # added in the library string - an rpath is not a library anyway, and at
92     # least for Gromacs this works on all CMake versions. This should be
93     # reasonably future-proof, since newer versions of CMake appear to handle
94     # the rpath automatically based on the provided library path, meaning
95     # the explicit rpath specification is no longer needed.
96     if(APPLE AND (CMAKE_VERSION VERSION_GREATER 2.8.11))
97         foreach(elem ${CUDA_LIBRARIES})
98             if(elem MATCHES "-Wl,.*")
99                 list(REMOVE_ITEM CUDA_LIBRARIES ${elem})
100             endif()
101         endforeach(elem)
102     endif()
103 endif()
105 # Depending on the current vale of GMX_GPU and GMX_GPU_AUTO:
106 # - OFF, FALSE: Will skip this detection/setup.
107 # - OFF, TRUE : Will keep GMX_GPU=OFF if no CUDA is detected, but will assemble
108 #               a warning message which will be issued at the end of the
109 #               configuration if GPU(s) were found in the build system.
110 # - ON , FALSE: The user requested GPU build and this requires CUDA, so we will
111 #               fail if it is not available.
112 # - ON , TRUE : Can't happen (GMX_GPU=ON can only be user-set at this point)
113 if((GMX_GPU OR GMX_GPU_AUTO) AND NOT GMX_GPU_DETECTION_DONE)
114     if (EXISTS ${CUDA_TOOLKIT_ROOT_DIR})
115         set(CUDA_FOUND TRUE CACHE INTERNAL "Whether the CUDA toolkit was found" FORCE)
116     else()
117         set(CUDA_FOUND FALSE CACHE INTERNAL "Whether the CUDA toolkit was found" FORCE)
118     endif()
120     # assemble warning/error message
121     if (GMX_DETECT_GPU_AVAILABLE)
122         set(_msg "${GMX_DETECT_GPU_COUNT} NVIDIA GPU(s) found in the system")
124         # append GPU names
125         if (NOT GMX_DETECT_GPU_INFO STREQUAL "")
126             set(_msg "${_msg}:")
127             foreach(gpu ${GMX_DETECT_GPU_INFO})
128                 set(_msg "${_msg}
129 ${gpu}")
130             endforeach()
131         endif()
133         # TODO remove the second part of the message when we'll have compute
134         # capability information from the detection.
135         set(_msg "${_msg}
136 Compute capability information not available, consult the NVIDIA website:
137 https://developer.nvidia.com/cuda-gpus")
138     endif()
140         set(CUDA_NOTFOUND_MESSAGE "mdrun supports native GPU acceleration on NVIDIA hardware with compute capability >= ${REQUIRED_CUDA_COMPUTE_CAPABILITY} (Fermi or later). This requires the NVIDIA CUDA toolkit, which was not found. Its location can be hinted by setting the CUDA_TOOLKIT_ROOT_DIR CMake option (does not work as an environment variable). The typical location would be /usr/local/cuda[-version]. Note that CPU or GPU acceleration can be selected at runtime.
142 ${_msg}")
143         unset(_msg)
145     if (NOT CUDA_FOUND)
146         if (GMX_GPU_AUTO)
147             # Disable GPU acceleration in auto mode
148             message(STATUS "No compatible CUDA toolkit found (v4.0+), disabling native GPU acceleration")
149             set_property(CACHE GMX_GPU PROPERTY VALUE OFF)
150             set(CUDA_NOTFOUND_AUTO ON)
151         else()
152             # the user requested CUDA, but it wasn't found
153             message(FATAL_ERROR "${CUDA_NOTFOUND_MESSAGE}")
154         endif()
155     else()
156         if (GMX_GPU_AUTO)
157             message(STATUS "Enabling native GPU acceleration")
158             set_property(CACHE GMX_GPU PROPERTY VALUE ON)
159         endif()
160     endif() # NOT CUDA_FOUND
161 endif()
163 # Try to find NVML if a GPU accelerated binary should be build.
164 if (GMX_GPU)
165     if (DEFINED NVML_LIBRARY)
166         set(NVML_FIND_QUIETLY TRUE)
167     endif()
168     find_package(NVML)
169     option(GMX_USE_NVML "Use NVML support for better CUDA performance" ${NVML_FOUND})
170     mark_as_advanced(GMX_USE_NVML)
171     if(GMX_USE_NVML)
172         if(NVML_FOUND)
173             include_directories(SYSTEM ${NVML_INCLUDE_DIR})
174             set(HAVE_NVML 1)
175             list(APPEND GMX_EXTRA_LIBRARIES ${NVML_LIBRARY})
176         else()
177             message(FATAL_ERROR "NVML support was required, but was not detected. Please consult the install guide.")
178         endif()
179     endif()
180 endif()
182 # Annoyingly enough, FindCUDA leaves a few variables behind as non-advanced.
183 # We need to mark these advanced outside the conditional, otherwise, if the
184 # user turns GMX_GPU=OFF after a failed cmake pass, these variables will be
185 # left behind in the cache.
186 mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_SDK_ROOT_DIR CUDA_VERBOSE_BUILD # cmake 2.8.9 still spews these, check again when requirements change
187                  CUDA_SEPARABLE_COMPILATION      # not present at least with cmake 3.2, remove when required
188                  CUDA_USE_STATIC_CUDA_RUNTIME    # since cmake 3.3
189                  CUDA_dl_LIBRARY CUDA_rt_LIBRARY # - || -
190                  )
191 if(NOT GMX_GPU)
192     mark_as_advanced(CUDA_TOOLKIT_ROOT_DIR)
193 endif()
195 # Try to execute ${CUDA_NVCC_EXECUTABLE} --version and set the output
196 # (or an error string) in the argument variable.
197 # Note that semicolon is used as separator for nvcc.
199 # Parameters:
200 #   COMPILER_INFO   - [output variable] string with compiler path, ID and
201 #                     some compiler-provided information
202 #   COMPILER_FLAGS  - [output variable] flags for the compiler
204 macro(get_cuda_compiler_info COMPILER_INFO COMPILER_FLAGS)
205     if(CUDA_NVCC_EXECUTABLE)
207         # Get the nvcc version string. This is multi-line, but since it is only 4 lines
208         # and might change in the future it is better to store than trying to parse out
209         # the version from the current format.
210         execute_process(COMMAND ${CUDA_NVCC_EXECUTABLE} --version
211             RESULT_VARIABLE _nvcc_version_res
212             OUTPUT_VARIABLE _nvcc_version_out
213             ERROR_VARIABLE  _nvcc_version_err
214             OUTPUT_STRIP_TRAILING_WHITESPACE)
215         if (${_nvcc_version_res} EQUAL 0)
216             # Fix multi-line mess: Replace newline with ";" so we can use it in a define
217             string(REPLACE "\n" ";" _nvcc_info_singleline ${_nvcc_version_out})
218             SET(${COMPILER_INFO} "${CUDA_NVCC_EXECUTABLE} ${_nvcc_info_singleline}")
219             string(TOUPPER ${CMAKE_BUILD_TYPE} _build_type)
220             SET(_compiler_flags "${CUDA_NVCC_FLAGS_${_build_type}}")
221             if(CUDA_PROPAGATE_HOST_FLAGS)
222                 string(REGEX REPLACE "[ ]+" ";" _cxx_flags_nospace "${BUILD_CXXFLAGS}")
223             endif()
224             SET(${COMPILER_FLAGS} "${CUDA_NVCC_FLAGS}${CUDA_NVCC_FLAGS_${_build_type}}; ${_cxx_flags_nospace}")
225         else()
226             SET(${COMPILER_INFO} "N/A")
227             SET(${COMPILER_FLAGS} "N/A")
228         endif()
229     endif()
230 endmacro ()
232 macro(gmx_gpu_setup)
233     # set up nvcc options
234     include(gmxManageNvccConfig)
236     gmx_check_if_changed(_cuda_version_changed CUDA_VERSION)
238     # Generate CUDA RT API version string which will end up in config.h
239     # We do this because nvcc is silly enough to not define its own version
240     # (which should match the CUDA runtime API version AFAICT) and we want to
241     # avoid creating the fragile dependency on cuda_runtime_api.h.
242     #
243     # NOTE: CUDA v7.5 is expected to have nvcc define it own version, so in the
244     # future we should switch to using that version string instead of our own.
245     if (NOT GMX_CUDA_VERSION OR _cuda_version_changed)
246         MATH(EXPR GMX_CUDA_VERSION "${CUDA_VERSION_MAJOR}*1000 + ${CUDA_VERSION_MINOR}*10")
247     endif()
249     if (_cuda_version_changed)
250         # check the generated CUDA API version against the one present in cuda_runtime_api.h
251         try_compile(_get_cuda_version_compile_res
252             ${CMAKE_BINARY_DIR}
253             ${CMAKE_SOURCE_DIR}/cmake/TestCUDAVersion.c
254             COMPILE_DEFINITIONS "-DGMX_CUDA_VERSION=${GMX_CUDA_VERSION}"
255             CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${CUDA_TOOLKIT_INCLUDE}"
256             OUTPUT_VARIABLE _get_cuda_version_compile_out)
258         if (NOT _get_cuda_version_compile_res)
259             if (_get_cuda_version_compile_out MATCHES "CUDA version mismatch")
260                 message(FATAL_ERROR "The CUDA API version generated internally from the compiler version does not match the version reported by cuda.h. This means either that the CUDA detection picked up mismatching nvcc and the CUDA headers (likely not part of the same toolkit installation) or that there is an error in the internal version generation. If you are sure that it is not the former causing the error (check the relevant cache variables), define the GMX_CUDA_VERSION cache variable to work around the error.")
261             else()
262                 message(FATAL_ERROR "Could not detect CUDA runtime API version")
263             endif()
264         endif()
265     endif()
267     # texture objects are supported in CUDA 5.0 and later
268     if (CUDA_VERSION VERSION_GREATER 4.999)
269         set(HAVE_CUDA_TEXOBJ_SUPPORT 1)
270     endif()
272     # Atomic operations used for polling wait for GPU
273     # (to avoid the cudaStreamSynchronize + ECC bug).
274     # ThreadMPI is now always included. Thus, we don't check for Atomics anymore here.
276     # no OpenMP is no good!
277     if(NOT GMX_OPENMP)
278         message(WARNING "To use GPU acceleration efficiently, mdrun requires OpenMP multi-threading. Without OpenMP a single CPU core can be used with a GPU which is not optimal. Note that with MPI multiple processes can be forced to use a single GPU, but this is typically inefficient. You need to set both C and C++ compilers that support OpenMP (CC and CXX environment variables, respectively) when using GPUs.")
279     endif()
280 endmacro()