Skip to content

Commit

Permalink
Support throttling and resetting thread use via OpenMP functions
Browse files Browse the repository at this point in the history
  • Loading branch information
eddelbuettel committed Oct 29, 2023
1 parent 5176e7d commit efe5fe6
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 4 deletions.
16 changes: 16 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
2023-10-29 Dirk Eddelbuettel <[email protected]>

* src/RcppArmadillo.cpp (armadillo_get_number_of_omp_threads)
(armadillo_set_number_of_omp_threads): New helper functions
* src/RcppExports.cpp: Regenerated
* R/RcppExports.R: Idem
* man/armadillo_get_number_of_omp_threads.Rd: Documentation

* R/init.R (.onLoad): Store initial thread count
* R/init.R (armadillo_throttle_cores, armadillo_reset_cores):
Tread throtte and reset helper functions
* man/armadillo_throttle_cores.Rd: Documentation

* man/fastLm.Rd: Illustration of use of throttle and reset function
* NAMESPACE: Export new functions

2023-10-14 Dirk Eddelbuettel <[email protected]>

* DESCRIPTION (Version, Date): RcppArmadillo 0.12.6.5.0
Expand Down
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ Imports: Rcpp (>= 0.11.0), stats, utils, methods
Suggests: tinytest, Matrix (>= 1.3.0), pkgKitten, reticulate, slam
URL: https://github.com/RcppCore/RcppArmadillo, https://dirk.eddelbuettel.com/code/rcpp.armadillo.html
BugReports: https://github.com/RcppCore/RcppArmadillo/issues
RoxygenNote: 6.0.1
10 changes: 7 additions & 3 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ export("fastLmPure",
"RcppArmadillo.package.skeleton",
"armadillo_version",
"armadillo_set_seed",
"armadillo_set_seed_random")
"armadillo_set_seed_random",

"armadillo_throttle_cores",
"armadillo_reset_cores",
"armadillo_set_number_of_omp_threads",
"armadillo_set_number_of_omp_threads"
)
S3method("fastLm", "default")
S3method("fastLm", "formula")
S3method("predict", "fastLm")
S3method("print", "fastLm")
S3method("summary", "fastLm")
S3method("print", "summary.fastLm")


15 changes: 15 additions & 0 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ armadillo_set_seed <- function(val) {
invisible(.Call(`_RcppArmadillo_armadillo_set_seed`, val))
}

#' Report (or Set) Maximum Number of OpenMP Threads
#'
#' @param n Number of threads to be set
#' @return For the getter, and on a system with OpenMP, the maximum
#' number of threads that OpenMP may be using and on systems without it,
#' one. The setter does not return a value.
armadillo_get_number_of_omp_threads <- function() {
.Call(`_RcppArmadillo_armadillo_get_number_of_omp_threads`)
}

#' @rdname armadillo_get_number_of_omp_threads
armadillo_set_number_of_omp_threads <- function(n) {
invisible(.Call(`_RcppArmadillo_armadillo_set_number_of_omp_threads`, n))
}

fastLm_impl <- function(X, y) {
.Call(`_RcppArmadillo_fastLm_impl`, X, y)
}
Expand Down
40 changes: 40 additions & 0 deletions R/init.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## init.R: Startup
##
## Copyright (C) 2023 Dirk Eddelbuettel
##
## This file is part of RcppArmadillo.
##
## RcppArmadillo is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 2 of the License, or
## (at your option) any later version.
##
## RcppArmadillo is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with RcppArmadillo. If not, see <http://www.gnu.org/licenses/>.

.pkgenv <- new.env(parent=emptyenv())

.onLoad <- function(libname, pkgname) {
.pkgenv[["omp_threads"]] <- armadillo_get_number_of_omp_threads()
}

##' Throttle (or Reset) (Rcpp)Armadillo to Two Cores
##'
##' Helper functions to throttle use of cores by RcppArmadillo-internal
##' code on systems with OpenMP. On package load, the initial value is
##' saved and used to reset the value.
##' @param n Integer value of desired cores, default is two
armadillo_throttle_cores <- function(n = 2) {
armadillo_set_number_of_omp_threads(n)
}

##' @rdname armadillo_throttle_cores
armadillo_reset_cores <- function() {
n <- .pkgenv[["omp_threads"]]
armadillo_set_number_of_omp_threads(n)
}
22 changes: 22 additions & 0 deletions man/armadillo_get_number_of_omp_threads.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions man/armadillo_throttle_cores.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions man/fastLm.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ fastLm(X, \dots)
Romain Francois, Dirk Eddelbuettel, Douglas Bates and Binxiang Ni.
}
\examples{
\dontshow{
## as an illustration, the example is computationally inexpensive
## and does not require this per se
armadillo_throttle_cores(2)
}
data(trees, package="datasets")

## bare-bones direct interface
Expand All @@ -89,5 +94,7 @@ fastLm(X, \dots)
dd$y <- mm \%*\% seq_len(ncol(mm)) + rnorm(nrow(mm), sd = 0.1)
summary(lm(y ~ f1 * f2, dd)) # detects rank deficiency
summary(fastLm(y ~ f1 * f2, dd)) # some huge coefficients

\dontshow{armadillo_reset_cores()}
}
\keyword{regression}
25 changes: 24 additions & 1 deletion src/RcppArmadillo.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

// RcppArmadillo.cpp: Rcpp/Armadillo glue
//
// Copyright (C) 2010 - 2020 Dirk Eddelbuettel, Romain Francois and Douglas Bates
// Copyright (C) 2010 - 2023 Dirk Eddelbuettel, Romain Francois and Douglas Bates
//
// This file is part of RcppArmadillo.
//
Expand Down Expand Up @@ -90,3 +90,26 @@ void armadillo_set_seed(unsigned int val) {
//Rcpp::Rcout << "Setting value " << val << std::endl;
arma::arma_rng::set_seed(val); // set the seed to given value
}

//' Report (or Set) Maximum Number of OpenMP Threads
//'
//' @param n Number of threads to be set
//' @return For the getter, and on a system with OpenMP, the maximum
//' number of threads that OpenMP may be using and on systems without it,
//' one. The setter does not return a value.
// [[Rcpp::export]]
int armadillo_get_number_of_omp_threads() {
#ifdef _OPENMP
return omp_get_max_threads();
#else
return 1;
#endif
}

//' @rdname armadillo_get_number_of_omp_threads
// [[Rcpp::export]]
void armadillo_set_number_of_omp_threads(int n) {
#ifdef _OPENMP
omp_set_num_threads(n);
#endif

This comment has been minimized.

Copy link
@conradsnicta

conradsnicta Oct 30, 2023

Contributor

@eddelbuettel If OpenMP is not enabled, the compiler may warn (for example, under -Wall) that parameter n is unused.

Suggest to change the function to:

#ifdef _OPENMP
    omp_set_num_threads(n);
#else
    (void)(n);  // prevent unused variable warning
#endif

This comment has been minimized.

Copy link
@conradsnicta

conradsnicta Oct 30, 2023

Contributor

PS. Suggest to also sanitise the value of n before passing it to omp_set_num_threads(). Valid values are >= 1. For example:

omp_set_num_threads( (std::max)(int(1), n) );

In the above code, the std::max function is explicitly placed in brackets, ie. (std::max). This is a workaround for problems with Windoze, where there may be a max macro that causes conflicts.

This comment has been minimized.

Copy link
@eddelbuettel

eddelbuettel Oct 30, 2023

Author Member

Ah, thanks. I wondered about that fairly elaborate setup of yours.

R being what it is, it supplies one build system for R (aka "Rtools") and I think it may not include OpenMP. Similar on that OS that ships with that fancy hardware from Cupertino, California, it is also always an extra step to get OpenMP to actually get to use all those core money has been spent on ...

This comment has been minimized.

Copy link
@coatless

coatless Oct 30, 2023

Contributor

OpenMP is no longer available by default on R since like R 4.1 or R 4.2. Though, you can drop OpenMP headers into /usr/local/lib and /usr/local/include that are related to the xcode/llvm version installed. But, if you upgrade Xcode or Xcode CLI, then new headers must be obtained, and on... So, here be thorns.

This comment has been minimized.

Copy link
@eddelbuettel

eddelbuettel Oct 30, 2023

Author Member

Wait, come again (and as you know I am several arm's lengths from macOS ...) are you saying "essentially no OpenMP, ever" (unless you do local surgery) ?

The mind boggles, The hardware sure is nice. The software setup, though, is [and here my lawyer removes my keyboard access to protect me ...]

This comment has been minimized.

Copy link
@coatless

coatless Oct 30, 2023

Contributor

That's the current status quo for official binaries due to how FUBAR'd the prior clang toolchain move was.

This comment has been minimized.

Copy link
@eddelbuettel

eddelbuettel Oct 30, 2023

Author Member

That is so sad.

}
22 changes: 22 additions & 0 deletions src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ BEGIN_RCPP
return R_NilValue;
END_RCPP
}
// armadillo_get_number_of_omp_threads
int armadillo_get_number_of_omp_threads();
RcppExport SEXP _RcppArmadillo_armadillo_get_number_of_omp_threads() {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
rcpp_result_gen = Rcpp::wrap(armadillo_get_number_of_omp_threads());
return rcpp_result_gen;
END_RCPP
}
// armadillo_set_number_of_omp_threads
void armadillo_set_number_of_omp_threads(int n);
RcppExport SEXP _RcppArmadillo_armadillo_set_number_of_omp_threads(SEXP nSEXP) {
BEGIN_RCPP
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< int >::type n(nSEXP);
armadillo_set_number_of_omp_threads(n);
return R_NilValue;
END_RCPP
}
// fastLm_impl
Rcpp::List fastLm_impl(const arma::mat& X, const arma::colvec& y);
RcppExport SEXP _RcppArmadillo_fastLm_impl(SEXP XSEXP, SEXP ySEXP) {
Expand All @@ -58,6 +78,8 @@ static const R_CallMethodDef CallEntries[] = {
{"_RcppArmadillo_armadillo_version", (DL_FUNC) &_RcppArmadillo_armadillo_version, 1},
{"_RcppArmadillo_armadillo_set_seed_random", (DL_FUNC) &_RcppArmadillo_armadillo_set_seed_random, 0},
{"_RcppArmadillo_armadillo_set_seed", (DL_FUNC) &_RcppArmadillo_armadillo_set_seed, 1},
{"_RcppArmadillo_armadillo_get_number_of_omp_threads", (DL_FUNC) &_RcppArmadillo_armadillo_get_number_of_omp_threads, 0},
{"_RcppArmadillo_armadillo_set_number_of_omp_threads", (DL_FUNC) &_RcppArmadillo_armadillo_set_number_of_omp_threads, 1},
{"_RcppArmadillo_fastLm_impl", (DL_FUNC) &_RcppArmadillo_fastLm_impl, 2},
{NULL, NULL, 0}
};
Expand Down

0 comments on commit efe5fe6

Please sign in to comment.