From cb3ed404cff3636248b04e7081bfccfefec3e3d8 Mon Sep 17 00:00:00 2001 From: Philip Hyunsu Cho Date: Tue, 28 Jan 2020 12:37:22 -0800 Subject: [PATCH] [R] Enable OpenMP with AppleClang in XGBoost R package (#5240) * [R] Enable OpenMP with AppleClang in XGBoost R package * Dramatically simplify install doc --- Makefile | 2 ++ R-package/configure | 41 +++++++++++++++-------------- R-package/configure.ac | 18 ++++++++++--- R-package/src/Makevars.in | 2 +- doc/build.rst | 54 ++++++++++----------------------------- 5 files changed, 51 insertions(+), 66 deletions(-) diff --git a/Makefile b/Makefile index 21f3038db..b3bed8658 100644 --- a/Makefile +++ b/Makefile @@ -261,6 +261,8 @@ Rpack: clean_all sed -i -e 's/-pthread/$$\(SHLIB_PTHREAD_FLAGS\)/g' xgboost/src/Makevars.win sed -i -e 's/@ENDIAN_FLAG@/-DDMLC_CMAKE_LITTLE_ENDIAN=1/g' xgboost/src/Makevars.win sed -i -e 's/@BACKTRACE_LIB@//g' xgboost/src/Makevars.win + sed -i -e 's/@OPENMP_LIB@//g' xgboost/src/Makevars.win + rm -f xgboost/src/Makevars.win-e # OSX sed create this extra file; remove it bash R-package/remove_warning_suppression_pragma.sh rm xgboost/remove_warning_suppression_pragma.sh diff --git a/R-package/configure b/R-package/configure index 3e27bc13e..8dab660a1 100755 --- a/R-package/configure +++ b/R-package/configure @@ -585,6 +585,7 @@ ac_subst_vars='LTLIBOBJS LIBOBJS BACKTRACE_LIB ENDIAN_FLAG +OPENMP_LIB OPENMP_CXXFLAGS OBJEXT EXEEXT @@ -612,7 +613,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -682,7 +682,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -935,15 +934,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1081,7 +1071,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1234,7 +1224,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1827,11 +1816,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -### Check whether backtrace() is part of libc or the external lib libexecinfo -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Backtrace lib" >&5 -$as_echo_n "checking Backtrace lib... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 -$as_echo "" >&6; } +# Use this line to set CC variable to a C compiler ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2622,6 +2607,12 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu +### Check whether backtrace() is part of libc or the external lib libexecinfo +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking Backtrace lib" >&5 +$as_echo_n "checking Backtrace lib... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lexecinfo" >&5 $as_echo_n "checking for backtrace in -lexecinfo... " >&6; } if ${ac_cv_lib_execinfo_backtrace+:} false; then : @@ -2706,7 +2697,8 @@ fi if test `uname -s` = "Darwin" then - OPENMP_CXXFLAGS="\$(SHLIB_OPENMP_CXXFLAGS)" + OPENMP_CXXFLAGS='-Xclang -fopenmp' + OPENMP_LIB='/usr/local/lib/libomp.dylib' ac_pkg_openmp=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenMP will work in a package" >&5 $as_echo_n "checking whether OpenMP will work in a package... " >&6; } @@ -2716,22 +2708,29 @@ $as_echo_n "checking whether OpenMP will work in a package... " >&6; } int main () { - return omp_get_num_threads (); + return (omp_get_max_threads() <= 1); ; return 0; } _ACEOF - PKG_CFLAGS="${OPENMP_CFLAGS}" PKG_LIBS="${OPENMP_CFLAGS}" "$RBIN" CMD SHLIB conftest.c 1>&5 2>&5 && "$RBIN" --vanilla -q -e "dyn.load(paste('conftest',.Platform\$dynlib.ext,sep=''))" 1>&5 2>&5 && ac_pkg_openmp=yes + ${CC} -o conftest conftest.c /usr/local/lib/libomp.dylib -Xclang -fopenmp 2>/dev/null && ./conftest && ac_pkg_openmp=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_pkg_openmp}" >&5 $as_echo "${ac_pkg_openmp}" >&6; } if test "${ac_pkg_openmp}" = no; then OPENMP_CXXFLAGS='' + OPENMP_LIB='' + echo '*****************************************************************************************' + echo 'WARNING: OpenMP is unavailable on this Mac OSX system. Training speed may be suboptimal.' + echo ' To use all CPU cores for training jobs, you should install OpenMP by running\n' + echo ' brew install libomp' + echo '*****************************************************************************************' fi fi + ac_config_files="$ac_config_files src/Makevars" cat >confcache <<\_ACEOF diff --git a/R-package/configure.ac b/R-package/configure.ac index 0f07891ff..c683a9483 100644 --- a/R-package/configure.ac +++ b/R-package/configure.ac @@ -4,6 +4,9 @@ AC_PREREQ(2.62) AC_INIT([xgboost],[0.6-3],[],[xgboost],[]) +# Use this line to set CC variable to a C compiler +AC_PROG_CC + ### Check whether backtrace() is part of libc or the external lib libexecinfo AC_MSG_CHECKING([Backtrace lib]) AC_MSG_RESULT([]) @@ -25,19 +28,26 @@ fi if test `uname -s` = "Darwin" then - OPENMP_CXXFLAGS="\$(SHLIB_OPENMP_CXXFLAGS)" + OPENMP_CXXFLAGS='-Xclang -fopenmp' + OPENMP_LIB='/usr/local/lib/libomp.dylib' ac_pkg_openmp=no AC_MSG_CHECKING([whether OpenMP will work in a package]) - AC_LANG_CONFTEST( - [AC_LANG_PROGRAM([[#include ]], [[ return omp_get_num_threads (); ]])]) - PKG_CFLAGS="${OPENMP_CFLAGS}" PKG_LIBS="${OPENMP_CFLAGS}" "$RBIN" CMD SHLIB conftest.c 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD && "$RBIN" --vanilla -q -e "dyn.load(paste('conftest',.Platform\$dynlib.ext,sep=''))" 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD && ac_pkg_openmp=yes + AC_LANG_CONFTEST([AC_LANG_PROGRAM([[#include ]], [[ return (omp_get_max_threads() <= 1); ]])]) + ${CC} -o conftest conftest.c /usr/local/lib/libomp.dylib -Xclang -fopenmp 2>/dev/null && ./conftest && ac_pkg_openmp=yes AC_MSG_RESULT([${ac_pkg_openmp}]) if test "${ac_pkg_openmp}" = no; then OPENMP_CXXFLAGS='' + OPENMP_LIB='' + echo '*****************************************************************************************' + echo 'WARNING: OpenMP is unavailable on this Mac OSX system. Training speed may be suboptimal.' + echo ' To use all CPU cores for training jobs, you should install OpenMP by running\n' + echo ' brew install libomp' + echo '*****************************************************************************************' fi fi AC_SUBST(OPENMP_CXXFLAGS) +AC_SUBST(OPENMP_LIB) AC_SUBST(ENDIAN_FLAG) AC_SUBST(BACKTRACE_LIB) AC_CONFIG_FILES([src/Makevars]) diff --git a/R-package/src/Makevars.in b/R-package/src/Makevars.in index e1beb5cdc..ac25b5077 100644 --- a/R-package/src/Makevars.in +++ b/R-package/src/Makevars.in @@ -18,7 +18,7 @@ $(foreach v, $(XGB_RFLAGS), $(warning $(v))) PKG_CPPFLAGS= -I$(PKGROOT)/include -I$(PKGROOT)/dmlc-core/include -I$(PKGROOT)/rabit/include -I$(PKGROOT) $(XGB_RFLAGS) PKG_CXXFLAGS= @OPENMP_CXXFLAGS@ @ENDIAN_FLAG@ -pthread -PKG_LIBS = @OPENMP_CXXFLAGS@ @ENDIAN_FLAG@ @BACKTRACE_LIB@ -pthread +PKG_LIBS = @OPENMP_CXXFLAGS@ @OPENMP_LIB@ @ENDIAN_FLAG@ @BACKTRACE_LIB@ -pthread OBJECTS= ./xgboost_R.o ./xgboost_custom.o ./xgboost_assert.o ./init.o\ $(PKGROOT)/amalgamation/xgboost-all0.o $(PKGROOT)/amalgamation/dmlc-minimum0.o\ $(PKGROOT)/rabit/src/engine_empty.o $(PKGROOT)/rabit/src/c_api.o diff --git a/doc/build.rst b/doc/build.rst index 634cf6047..38bd21a3f 100644 --- a/doc/build.rst +++ b/doc/build.rst @@ -316,13 +316,21 @@ R Package Installation Installing pre-packaged version ------------------------------- -You can install xgboost from CRAN just like any other R package: +You can install XGBoost from CRAN just like any other R package: .. code-block:: R - install.packages("xgboost") + install.packages("xgboost") -For OSX users, single-threaded version will be installed. So only one thread will be used for training. To enable use of multiple threads (and utilize capacity of multi-core CPUs), see the section :ref:`osx_multithread` to install XGBoost from source. +.. note:: Using all CPU cores (threads) on Mac OSX + + If you are using Mac OSX, you should first install OpenMP library (``libomp``) by running + + .. code-block:: bash + + brew install libomp + + and then run ``install.packages("xgboost")``. Without OpenMP, XGBoost will only use a single CPU core, leading to suboptimal training speed. Installing the development version ---------------------------------- @@ -339,48 +347,14 @@ Thus, one has to run git to check out the code first: cd xgboost git submodule init git submodule update - cd R-package - R CMD INSTALL . - -If the last line fails because of the error ``R: command not found``, it means that R was not set up to run from command line. -In this case, just start R as you would normally do and run the following: - -.. code-block:: R - - setwd('wherever/you/cloned/it/xgboost/R-package/') - install.packages('.', repos = NULL, type="source") - -The package could also be built and installed with CMake (and Visual C++ 2015 on Windows) using instructions from :ref:`r_gpu_support`, but without GPU support (omit the ``-DUSE_CUDA=ON`` cmake parameter). - -If all fails, try `Building the shared library`_ to see whether a problem is specific to R package or not. - -.. _osx_multithread: - -Installing R package on Mac OSX with multi-threading ----------------------------------------------------- - -First, obtain ``gcc-9`` and ``OpenMP`` with Homebrew (https://brew.sh/) to enable multi-threading (i.e. using multiple CPU threads for training). The default Apple Clang compiler does not support OpenMP, so using the default compiler would have disabled multi-threading. - -.. code-block:: bash - - brew install gcc@9 libomp - -Now, clone the repository: - -.. code-block:: bash - - git clone --recursive https://github.com/dmlc/xgboost - -Create the ``build/`` directory and invoke CMake with option ``R_LIB=ON``. Make sure to add ``CC=gcc-9 CXX=g++-9`` so that Homebrew GCC is selected. After invoking CMake, you can install the R package by running ``make`` and ``make install``: - -.. code-block:: bash - mkdir build cd build - CC=gcc-9 CXX=g++-9 cmake .. -DR_LIB=ON + cmake .. -DR_LIB=ON make -j4 make install +If all fails, try `Building the shared library`_ to see whether a problem is specific to R package or not. + .. _r_gpu_support: Installing R package with GPU support