Refactor Ceres threading option configuration. - Previously we had separate variables for each of the threading backends, each of which were made mutually exclusive via cmake_dependent_option(). This has unfortunate side-effects when trying to disable options if they are not currently enabled, in which case they are not defined. - As all the threading options are mutually exclusive, this replaces all threading option variables with a single variable: CERES_THREADS, which is constrained to take the value of only the available threading backends. Change-Id: I0822eefbac9a30772907b7732add365b37cc8ca0
diff --git a/CMakeLists.txt b/CMakeLists.txt index f1f59ff..1ffcb2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -115,7 +115,22 @@ enable_testing() -include(CMakeDependentOption) +include(CeresThreadingModels) +include(PrettyPrintCMakeList) +find_available_ceres_threading_models(CERES_THREADING_MODELS_AVAILABLE) +pretty_print_cmake_list(PRETTY_CERES_THREADING_MODELS_AVAILABLE + ${CERES_THREADING_MODELS_AVAILABLE}) +message("-- Detected available Ceres threading models: " + "${PRETTY_CERES_THREADING_MODELS_AVAILABLE}") +set(CERES_THREADING_MODEL "${CERES_THREADING_MODEL}" CACHE STRING + "Ceres threading back-end" FORCE) +if (NOT CERES_THREADING_MODEL) + list(GET CERES_THREADING_MODELS_AVAILABLE 0 DEFAULT_THREADING_MODEL) + update_cache_variable(CERES_THREADING_MODEL ${DEFAULT_THREADING_MODEL}) +endif() +set_property(CACHE CERES_THREADING_MODEL PROPERTY STRINGS + ${CERES_THREADING_MODELS_AVAILABLE}) + option(MINIGLOG "Use a stripped down version of glog." OFF) option(GFLAGS "Enable Google Flags." ON) option(SUITESPARSE "Enable SuiteSparse." ON) @@ -128,18 +143,6 @@ option(CUSTOM_BLAS "Use handcoded BLAS routines (usually faster) instead of Eigen." ON) -# Multithreading using OpenMP -cmake_dependent_option( - OPENMP "Enable threaded solving in Ceres (requires OpenMP)" ON - "NOT TBB;NOT CXX11_THREADS" OFF) -# Multithreading using TBB -cmake_dependent_option( - TBB "Enable threaded solving in Ceres with TBB (requires TBB and C++11)" OFF - "NOT OPENMP;NOT CXX11_THREADS" OFF) -# Multithreading using C++11 primitives. -cmake_dependent_option( - CXX11_THREADS "Enable threaded solving in Ceres with C++11 primitives" OFF - "NOT OPENMP;NOT TBB" OFF) # Enable the use of Eigen as a sparse linear algebra library for # solving the nonlinear least squares problems. option(EIGENSPARSE "Enable Eigen as a sparse linear algebra library." ON) @@ -412,46 +415,7 @@ message("-- Disabling custom blas") endif (NOT CUSTOM_BLAS) -if (OPENMP) - # Find quietly, as we can continue without OpenMP if it is not found. - find_package(OpenMP QUIET) - if (OPENMP_FOUND) - message("-- Building with OpenMP.") - list(APPEND CERES_COMPILE_OPTIONS CERES_USE_OPENMP) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - else (OPENMP_FOUND) - message("-- Failed to find OpenMP, disabling. This is expected on " - "Clang < 3.8, and at least Xcode <= 8. See Ceres documentation for " - "instructions to build with LLVM from Homebrew to enable OpenMP on OS X.") - update_cache_variable(OPENMP OFF) - endif (OPENMP_FOUND) -else (OPENMP) - message("-- Building without OpenMP, disabling.") -endif (OPENMP) - -if (TBB) - find_package(TBB QUIET) - if (TBB_FOUND) - message("-- Building with TBB (version: ${TBB_VERSION}).") - list(APPEND CERES_COMPILE_OPTIONS CERES_USE_TBB) - include_directories(${TBB_INCLUDE_DIRS}) - else (TBB_FOUND) - message("-- Failed to find TBB, disabling.") - update_cache_variable(TBB OFF) - endif (TBB_FOUND) -endif() - -if (CXX11_THREADS) - message("-- Building with C++11 threads.") - list(APPEND CERES_COMPILE_OPTIONS CERES_USE_CXX11_THREADS) -endif() - -if (NOT OPENMP AND NOT TBB AND NOT CXX11_THREADS) - message("-- Neither OpenMP, TBB or C++11 threads is enabled, " - "disabling multithreading.") - list(APPEND CERES_COMPILE_OPTIONS CERES_NO_THREADS) -endif (NOT OPENMP AND NOT TBB AND NOT CXX11_THREADS) +set_ceres_threading_model("${CERES_THREADING_MODEL}") if (BUILD_BENCHMARKS) find_package(benchmark QUIET)
diff --git a/cmake/CeresThreadingModels.cmake b/cmake/CeresThreadingModels.cmake new file mode 100644 index 0000000..910f4a8 --- /dev/null +++ b/cmake/CeresThreadingModels.cmake
@@ -0,0 +1,94 @@ +# Ceres Solver - A fast non-linear least squares minimizer +# Copyright 2018 Google Inc. All rights reserved. +# http://ceres-solver.org/ +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Google Inc. nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Author: alexs.mac@gmail.com (Alex Stewart) + +# Ordered by expected preference. +set(CERES_THREADING_MODELS "CXX11_THREADS;OPENMP;TBB;NO_THREADS") + +function(find_available_ceres_threading_models CERES_THREADING_MODELS_AVAILABLE_VAR) + set(CERES_THREADING_MODELS_AVAILABLE ${CERES_THREADING_MODELS}) + # Remove any threading models for which the dependencies are not available. + find_package(OpenMP QUIET) + if (NOT OPENMP_FOUND) + list(REMOVE_ITEM CERES_THREADING_MODELS_AVAILABLE "OPENMP") + endif() + find_package(TBB QUIET) + if (NOT TBB_FOUND) + list(REMOVE_ITEM CERES_THREADING_MODELS_AVAILABLE "TBB") + endif() + if (NOT CERES_THREADING_MODELS_AVAILABLE) + # At least NO_THREADS should never be removed. This check is purely + # protective against future threading model updates. + message(FATAL_ERROR "Ceres bug: Removed all threading models.") + endif() + set(${CERES_THREADING_MODELS_AVAILABLE_VAR} + ${CERES_THREADING_MODELS_AVAILABLE} PARENT_SCOPE) +endfunction() + +macro(set_ceres_threading_model_to_cxx11_threads) + list(APPEND CERES_COMPILE_OPTIONS CERES_USE_CXX11_THREADS) +endmacro() + +macro(set_ceres_threading_model_to_openmp) + find_package(OpenMP REQUIRED) + list(APPEND CERES_COMPILE_OPTIONS CERES_USE_OPENMP) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") +endmacro() + +macro(set_ceres_threading_model_to_tbb) + find_package(TBB REQUIRED) + list(APPEND CERES_COMPILE_OPTIONS CERES_USE_TBB) + include_directories(${TBB_INCLUDE_DIRS}) +endmacro() + +macro(set_ceres_threading_model_to_no_threads) + list(APPEND CERES_COMPILE_OPTIONS CERES_NO_THREADS) +endmacro() + +macro(set_ceres_threading_model CERES_THREADING_MODEL_TO_SET) + if ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "CXX11_THREADS") + set_ceres_threading_model_to_cxx11_threads() + elseif ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "OPENMP") + set_ceres_threading_model_to_openmp() + elseif ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "TBB") + set_ceres_threading_model_to_tbb() + elseif ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "NO_THREADS") + set_ceres_threading_model_to_no_threads() + else() + include(PrettyPrintCMakeList) + find_available_ceres_threading_models(_AVAILABLE_THREADING_MODELS) + pretty_print_cmake_list( + _AVAILABLE_THREADING_MODELS ${_AVAILABLE_THREADING_MODELS}) + message(FATAL_ERROR "Unknown threading model specified: " + "'${CERES_THREADING_MODEL_TO_SET}'. Available threading models for " + "this platform are: ${_AVAILABLE_THREADING_MODELS}") + endif() + message("-- Using Ceres threading model: ${CERES_THREADING_MODEL_TO_SET}") +endmacro()
diff --git a/cmake/PrettyPrintCMakeList.cmake b/cmake/PrettyPrintCMakeList.cmake new file mode 100644 index 0000000..067883c --- /dev/null +++ b/cmake/PrettyPrintCMakeList.cmake
@@ -0,0 +1,39 @@ +# Ceres Solver - A fast non-linear least squares minimizer +# Copyright 2018 Google Inc. All rights reserved. +# http://ceres-solver.org/ +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the name of Google Inc. nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# Authors: alexs.mac@gmail.com (Alex Stewart) + +# pretty_print_cmake_list( OUTPUT_VAR [item1 [item2 ... ]] ) +# +# Sets ${OUTPUT_VAR} in the caller's scope to a human-readable string +# representation of the list passed as the remaining arguments formed +# as: "[item1, item2, ..., itemN]". +function(pretty_print_cmake_list OUTPUT_VAR) + string(REPLACE ";" ", " PRETTY_LIST_STRING "[${ARGN}]") + set(${OUTPUT_VAR} "${PRETTY_LIST_STRING}" PARENT_SCOPE) +endfunction()
diff --git a/docs/source/installation.rst b/docs/source/installation.rst index e7951bf..b80dc25 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst
@@ -664,13 +664,10 @@ gains in the ``SPARSE_SCHUR`` solver, you can disable some of the template specializations by turning this ``OFF``. -#. ``OPENMP [Default: ON]``: On certain platforms like Android, - multi-threading with ``OpenMP`` is not supported. Turn this ``OFF`` - to disable multi-threading. - -#. ``TBB [Default: OFF]``: An alternative to ``OpenMP`` threading library that - uses Intel's Thread Building Blocks. This option is mutually - exclusive to ``OPENMP`` and ``CXX11_THREADS``. +#. ``CERES_THREADING_MODEL [Default: CXX11_THREADS > OPENMP > TBB > NO_THREADS]``: + Multi-threading backend Ceres should be compiled with. This will + automatically be set to only accept the available subset of threading + options in the CMake GUI. .. NOTE:: @@ -678,10 +675,6 @@ GPL/Commercial terms. From 2017.x versions onwards, TBB is licensed under the Apache 2.0 license (and commerical terms). -#. ``CXX11_THREADS [Default: OFF]``: An alternative to ``OpenMP`` - threading library that uses a C++11 thread-pool. This option - is mutually exclusive to ``OPENMP`` and ``TBB``. - #. ``BUILD_SHARED_LIBS [Default: OFF]``: By default Ceres is built as a static library, turn this ``ON`` to instead build Ceres as a shared library. @@ -859,12 +852,13 @@ #. ``SchurSpecializations``: Ceres built with Schur specializations (``SCHUR_SPECIALIZATIONS=ON``). -#. ``OpenMP``: Ceres built with OpenMP (``OPENMP=ON``). +#. ``OpenMP``: Ceres built with OpenMP (``CERES_THREADING_MODEL=OPENMP``). -#. ``TBB``: Ceres built with Intel Thread Building Blocks (TBB) (``TBB=ON``). +#. ``TBB``: Ceres built with Intel Thread Building Blocks (TBB) + (``CERES_THREADING_MODEL=TBB``). #. ``Multithreading``: Ceres built with *a* multithreading library. - This is equivalent to ``OpenMP`` **OR** ``TBB``. + This is equivalent to (``CERES_THREAD != NO_THREADS``). #. ``C++11``: Ceres built with C++11.
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt index 0532073..71996b6 100644 --- a/internal/ceres/CMakeLists.txt +++ b/internal/ceres/CMakeLists.txt
@@ -30,13 +30,27 @@ # Avoid 'xxx.cc has no symbols' warnings from source files which are 'empty' # when their enclosing #ifdefs are disabled. -if (CXX11_THREADS) +find_package(Threads QUIET) +if (CERES_THREADING_MODEL STREQUAL "CXX11_THREADS") set(CERES_PARALLEL_FOR_SRC parallel_for_cxx.cc thread_pool.cc) -elseif (OPENMP) +elseif (CERES_THREADING_MODEL STREQUAL "OPENMP") set(CERES_PARALLEL_FOR_SRC parallel_for_openmp.cc) -elseif (TBB) + if (CMAKE_COMPILER_IS_GNUCXX) + # OpenMP in GCC requires the GNU OpenMP library. + list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES gomp) + endif() + if (NOT MSVC) + # Add thread library dependencies for OpenMP to the Ceres target. + list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CMAKE_THREAD_LIBS_INIT}) + endif() +elseif (CERES_THREADING_MODEL STREQUAL "TBB") set(CERES_PARALLEL_FOR_SRC parallel_for_tbb.cc) -else() + list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${TBB_LIBRARIES}) + if (NOT MSVC) + # Add thread library dependencies for OpenMP to the Ceres target. + list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CMAKE_THREAD_LIBS_INIT}) + endif (NOT MSVC) +elseif (CERES_THREADING_MODEL STREQUAL "NO_THREADS") set(CERES_PARALLEL_FOR_SRC parallel_for_nothreads.cc) endif() @@ -193,23 +207,6 @@ list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${LAPACK_LIBRARIES}) endif () -if (OPENMP_FOUND) - # OpenMP support in Clang requires a non-GNU OpenMP library. - if (CMAKE_COMPILER_IS_GNUCXX) - list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES gomp) - endif() - if (NOT MSVC) - list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CMAKE_THREAD_LIBS_INIT}) - endif() -endif (OPENMP_FOUND) - -if (TBB_FOUND) - list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${TBB_LIBRARIES}) - if (NOT MSVC) - list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CMAKE_THREAD_LIBS_INIT}) - endif (NOT MSVC) -endif (TBB_FOUND) - set(CERES_LIBRARY_SOURCE ${CERES_INTERNAL_SRC} ${CERES_INTERNAL_HDRS}