From efe5fe68644c058bb498d1dd9e18429f40970cba Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Sun, 29 Oct 2023 12:18:22 -0500 Subject: [PATCH 1/4] Support throttling and resetting thread use via OpenMP functions --- ChangeLog | 16 +++++++++ DESCRIPTION | 1 + NAMESPACE | 10 ++++-- R/RcppExports.R | 15 ++++++++ R/init.R | 40 ++++++++++++++++++++++ man/armadillo_get_number_of_omp_threads.Rd | 22 ++++++++++++ man/armadillo_throttle_cores.Rd | 19 ++++++++++ man/fastLm.Rd | 7 ++++ src/RcppArmadillo.cpp | 25 +++++++++++++- src/RcppExports.cpp | 22 ++++++++++++ 10 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 R/init.R create mode 100644 man/armadillo_get_number_of_omp_threads.Rd create mode 100644 man/armadillo_throttle_cores.Rd diff --git a/ChangeLog b/ChangeLog index cb6a3da9..a7dc95ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2023-10-29 Dirk Eddelbuettel + + * 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 * DESCRIPTION (Version, Date): RcppArmadillo 0.12.6.5.0 diff --git a/DESCRIPTION b/DESCRIPTION index d983a79b..ad223a1c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -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 diff --git a/NAMESPACE b/NAMESPACE index 3c77fa0e..20a9665d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -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") - - diff --git a/R/RcppExports.R b/R/RcppExports.R index f30f9c9f..4c54e2e6 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -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) } diff --git a/R/init.R b/R/init.R new file mode 100644 index 00000000..81702d29 --- /dev/null +++ b/R/init.R @@ -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 . + +.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) +} diff --git a/man/armadillo_get_number_of_omp_threads.Rd b/man/armadillo_get_number_of_omp_threads.Rd new file mode 100644 index 00000000..2041f90c --- /dev/null +++ b/man/armadillo_get_number_of_omp_threads.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{armadillo_get_number_of_omp_threads} +\alias{armadillo_get_number_of_omp_threads} +\alias{armadillo_set_number_of_omp_threads} +\title{Report (or Set) Maximum Number of OpenMP Threads} +\usage{ +armadillo_get_number_of_omp_threads() + +armadillo_set_number_of_omp_threads(n) +} +\arguments{ +\item{n}{Number of threads to be set} +} +\value{ +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. +} +\description{ +Report (or Set) Maximum Number of OpenMP Threads +} diff --git a/man/armadillo_throttle_cores.Rd b/man/armadillo_throttle_cores.Rd new file mode 100644 index 00000000..482326a6 --- /dev/null +++ b/man/armadillo_throttle_cores.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/init.R +\name{armadillo_throttle_cores} +\alias{armadillo_throttle_cores} +\alias{armadillo_reset_cores} +\title{Throttle (or Reset) (Rcpp)Armadillo to Two Cores} +\usage{ +armadillo_throttle_cores(n = 2) + +armadillo_reset_cores() +} +\arguments{ +\item{n}{Integer value of desired cores, default is two} +} +\description{ +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. +} diff --git a/man/fastLm.Rd b/man/fastLm.Rd index 9c7e5e60..0f807557 100644 --- a/man/fastLm.Rd +++ b/man/fastLm.Rd @@ -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 @@ -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} diff --git a/src/RcppArmadillo.cpp b/src/RcppArmadillo.cpp index 83161f50..2568c099 100644 --- a/src/RcppArmadillo.cpp +++ b/src/RcppArmadillo.cpp @@ -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. // @@ -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 +} diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index d8b5dcc1..392149d3 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -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) { @@ -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} }; From 077c36b23df9609832cff0fbc2bffa8f9198fbf0 Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Sun, 29 Oct 2023 20:14:29 -0500 Subject: [PATCH 2/4] Add else clause to prevent some compiler warnings --- src/RcppArmadillo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/RcppArmadillo.cpp b/src/RcppArmadillo.cpp index 2568c099..4f9e23fa 100644 --- a/src/RcppArmadillo.cpp +++ b/src/RcppArmadillo.cpp @@ -111,5 +111,7 @@ int armadillo_get_number_of_omp_threads() { void armadillo_set_number_of_omp_threads(int n) { #ifdef _OPENMP omp_set_num_threads(n); +#else + (void)(n); // prevent unused variable warning #endif } From a8db424bd6aaeda2ceb897142d3c366d9c6591c7 Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Mon, 30 Oct 2023 08:03:02 -0500 Subject: [PATCH 3/4] Tweak codecov.yml --- .codecov.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.codecov.yml b/.codecov.yml index fd302d71..e8b841ca 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,6 +1,15 @@ coverage: precision: 1 + status: + project: + default: + target: 70% # the (on purpose low) required coverage value + threshold: 2% # the permitted delta in hitting the target + patch: + default: + target: 0% # the (on purpose low) required coverage value + comment: false ignore: From 01c2c201ce815ea2aa4cba513041c4e7e63fef73 Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Tue, 31 Oct 2023 14:29:07 -0500 Subject: [PATCH 4/4] Correct NAMESPACE --- NAMESPACE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 20a9665d..f3c50c6d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,7 +14,7 @@ export("fastLmPure", "armadillo_throttle_cores", "armadillo_reset_cores", - "armadillo_set_number_of_omp_threads", + "armadillo_get_number_of_omp_threads", "armadillo_set_number_of_omp_threads" ) S3method("fastLm", "default")