OpenMP и (Rcpp) Eigen - PullRequest
       19

OpenMP и (Rcpp) Eigen

0 голосов
/ 06 декабря 2018

Мне интересно, как написать код, который иногда использует распараллеливание OpenMP, встроенное в библиотеку Eigen, в то время как в других случаях используется распараллеливание, которое я определяю.Надеюсь, приведенный ниже фрагмент кода должен дать представление о моей проблеме.Я задаю этот вопрос на этапе проектирования моей библиотеки (извините, у меня нет примера работающего / неработающего кода).

#ifdef _OPENMP
  #include <omp.h>
#endif

#include <RcppEigen.h>

void fxn(..., int ncores=-1){
  if (ncores > 0) omp_set_num_threads(ncores);
  /*
  * Code with matrix products 
  * where I would like to use Eigen's 
  * OpenMP parallelization
  */ 

  #pragma omp parallel for
  for (int i=0; i < iter; i++){
  /* 
  * Code I would like to parallelize "myself"
  * even though it involves matrix products
  */
  }
}

Какова наилучшая практика для контроля баланса между собственным распараллеливанием Эйгена с OpenMP и моим собственным.

ОБНОВЛЕНИЕ:

Я написал простой пример и проверил предложение Ггаэля.Короче говоря, я скептически отношусь к тому, что это решает проблему, которую я представлял (или я делаю что-то еще неправильно - извинения, если это последнее).Обратите внимание, что при явном распараллеливании цикла for во время выполнения не происходит никаких изменений (даже медленное

#ifdef _OPENMP
  #include <omp.h>
#endif 
#include <RcppEigen.h>

using namespace Rcpp;
// [[Rcpp::plugins(openmp)]]

// [[Rcpp::export]]
Eigen::MatrixXd testing(Eigen::MatrixXd A, Eigen::MatrixXd B, int n_threads=1){
  Eigen::setNbThreads(n_threads);
  Eigen::MatrixXd C = A*B;
  Eigen::setNbThreads(1);
  for (int i=0; i < A.cols(); i++){
    A.col(i).array() = A.col(i).array()*B.col(i).array(); 
  }
  return A;
}

// [[Rcpp::export]]
Eigen::MatrixXd testing_omp(Eigen::MatrixXd A, Eigen::MatrixXd B, int n_threads=1){
  Eigen::setNbThreads(n_threads);
  Eigen::MatrixXd C = A*B;
  Eigen::setNbThreads(1);
  #pragma omp parallel for num_threads(n_threads)
  for (int i=0; i < A.cols(); i++){
    A.col(i).array() = A.col(i).array()*B.col(i).array(); 
  }
  return A;
}


/*** R
A <- matrix(rnorm(1000*1000), 1000, 1000)
B <- matrix(rnorm(1000*1000), 1000, 1000)
microbenchmark::microbenchmark(testing(A,B, n_threads=1),
                               testing_omp(A,B, n_threads=1),
                               testing(A,B, n_threads=8), 
                               testing_omp(A,B, n_threads=8), 
                               times=10)
*/

Unit: milliseconds
                             expr       min        lq      mean    median        uq       max neval cld
     testing(A, B, n_threads = 1) 169.74272 183.94500 212.83868 218.15756 236.97049 264.52183    10   b
 testing_omp(A, B, n_threads = 1) 166.53132 178.48162 210.54195 227.65258 234.16727 238.03961    10   b
     testing(A, B, n_threads = 8)  56.03258  61.16001  65.15763  62.67563  67.37089  83.43565    10  a 
 testing_omp(A, B, n_threads = 8)  54.18672  57.78558  73.70466  65.36586  67.24229 167.90310    10  a 

1 Ответ

0 голосов
/ 06 декабря 2018

Возможно, проще всего отключить / включить многопоточность Eigen во время выполнения:

Eigen::setNbThreads(1); // single thread mode
#pragma omp parallel for
for (int i=0; i < iter; i++){ 
  // Code I would like to parallelize "myself"
  // even though it involves matrix products
}
Eigen::setNbThreads(0); // restore default
...