26 #ifdef GETFEM_HAS_OPENMP 
   31 using bgeot::scalar_type;
 
   35 #ifdef GETFEM_HAS_OPENMP 
   37   std::recursive_mutex omp_guard::mutex;
 
   39   omp_guard::omp_guard()
 
   41        std::make_unique<std::lock_guard<std::recursive_mutex>>(mutex)
 
   45   local_guard::local_guard(std::recursive_mutex& m) :
 
   48       std::make_shared<std::lock_guard<std::recursive_mutex>>(m)
 
   52   local_guard lock_factory::get_lock()
 const{
 
   53     return local_guard{mutex};
 
   56   size_type global_thread_policy::this_thread() {
 
   57     return partition_master::get().get_current_partition();
 
   60   size_type global_thread_policy::num_threads(){
 
   61     return partition_master::get().get_nb_partitions();
 
   64   size_type true_thread_policy::this_thread() {
 
   65     return omp_get_thread_num();
 
   68   size_type true_thread_policy::num_threads(){
 
   69     return omp_get_max_threads();
 
   73     omp_set_num_threads(n);
 
   74     partition_master::get().check_threads();
 
   79     if(omp_get_num_threads() == 1 && omp_get_level() == 0) 
return false;
 
   81     if(omp_get_num_threads() == 1 && omp_get_level() == 1) 
return true;
 
   83     if(omp_in_parallel() == 1) 
return true;
 
   89     return omp_get_max_threads() == 1;
 
   93     return std::thread::hardware_concurrency();
 
   98   size_type global_thread_policy::this_thread() {
return 0;}
 
  100   size_type global_thread_policy::num_threads(){
return 1;}
 
  102   size_type true_thread_policy::this_thread() {
return 0;}
 
  104   size_type true_thread_policy::num_threads(){
return 1;}
 
  121     std::vector<std::exception_ptr> exceptions;
 
  123     void captureException(){
 
  124       exceptions[true_thread_policy::this_thread()] = std::current_exception();
 
  129       : exceptions(true_thread_policy::num_threads(), 
nullptr)
 
  132     template <
typename function, 
typename... parameters>
 
  133     void run(
function f, parameters... params){
 
  134         try {f(params...);} 
catch (...) {captureException();}
 
  137     std::vector<std::exception_ptr> caughtExceptions()
 const{
 
  138       std::vector<std::exception_ptr> non_empty_exceptions;
 
  139       for (
auto &&pException : exceptions){
 
  140         if (pException != 
nullptr) non_empty_exceptions.push_back(pException);
 
  142       return non_empty_exceptions;
 
  146       for (
auto &&pException : exceptions){
 
  147         if (pException != 
nullptr) std::rethrow_exception(pException);
 
  152   partition_iterator::partition_iterator(
 
  154     : master{m}, it{it_from_set}
 
  157   partition_iterator partition_iterator::operator++(){
 
  159     if (*
this != master.
end()) master.set_current_partition(*it);
 
  163   bool partition_iterator::operator==(
const partition_iterator &it1)
 const {
 
  167   bool partition_iterator::operator!=(
const partition_iterator &it1)
 const {
 
  168     return !(*
this == it1);
 
  171   size_type partition_iterator::operator*()
 const{
 
  175   partition_master partition_master::instance;
 
  177   partition_master& partition_master::get(){
 
  181   void partition_master::check_threads(){
 
  183     auto must_update = 
false;
 
  184     if (nb_user_threads != true_thread_policy::num_threads()){
 
  185       nb_user_threads = true_thread_policy::num_threads();
 
  188     if (nb_partitions < nb_user_threads && !partitions_set_by_user){
 
  189       nb_partitions = nb_user_threads;
 
  194       dal::singletons_manager::on_partitions_change();
 
  199     GMM_ASSERT1 (!partitions_set_by_user,
 
  200                  "Number of partitions can be set only once.");
 
  201     if (n > nb_partitions){
 
  203       nb_user_threads = true_thread_policy::num_threads();
 
  205       dal::singletons_manager::on_partitions_change();
 
  207     else if (n < nb_partitions){
 
  208       GMM_WARNING1(
"Not reducing number of partitions from " 
  209                    << nb_partitions <<
" to " << n <<
 
  210                    " as it might invalidate global storage.");
 
  212     partitions_set_by_user = 
true;
 
  216     GMM_ASSERT1(nb_user_threads == true_thread_policy::num_threads(),
 
  217                 "The number of omp threads was changed outside partition_master." 
  218                 "Please use getfem::set_num_threads for this.");
 
  219     current_partition = *(std::begin(partitions.thrd_cast()));
 
  230                   "Cannot change thread policy in parallel section.");
 
  236   partition_master::partition_master()
 
  237     : nb_user_threads{1}, nb_partitions{1} {
 
  238         partitions_updated = 
false;
 
  244     GMM_ASSERT2(behaviour == thread_behaviour::partition_threads ?
 
  245                 true_thread_policy::this_thread() < nb_partitions : 
true,
 
  246                 "Requesting current partition for thread " <<
 
  247                 true_thread_policy::this_thread() <<
 
  248                 " while number of partitions is " << nb_partitions
 
  250     return behaviour == thread_behaviour::partition_threads ?
 
  251            current_partition : true_thread_policy::this_thread();
 
  255     return behaviour == thread_behaviour::partition_threads ?
 
  256            nb_partitions : true_thread_policy::num_threads();
 
  259   void partition_master::set_current_partition(
size_type p){
 
  260     if (behaviour == thread_behaviour::partition_threads){
 
  261       GMM_ASSERT2(partitions.thrd_cast().count(p) != 0, 
"Internal error: " 
  262                   << p << 
" is not a valid partitions for thread " 
  263                   << true_thread_policy::this_thread()
 
  265       current_partition = p;
 
  269   void partition_master::rewind_partitions(){
 
  271       current_partition = *(std::begin(partitions.thrd_cast()));
 
  274       for (
size_type t = 0; t != partitions.num_threads(); ++t){
 
  275         current_partition(t) = *(std::begin(partitions(t)));
 
  280   void partition_master::update_partitions(){
 
  281     partitions_updated = 
false;
 
  285     if (partitions_updated) 
return;
 
  287     partitions = decltype(partitions){};
 
  288     current_partition = decltype(current_partition){};
 
  290     auto n_threads = true_thread_policy::num_threads();
 
  291     if(n_threads > nb_partitions){
 
  292       GMM_WARNING0(
"Using " << n_threads <<
 
  293                    " threads which is above the maximum number of partitions :" <<
 
  297     if (behaviour == thread_behaviour::partition_threads){
 
  298       for (
size_type t = 0; t != n_threads; ++t){
 
  299         auto partition_size = 
static_cast<size_type> 
  300                                 (std::ceil(
static_cast<scalar_type
>(nb_partitions) /
 
  301                                            static_cast<scalar_type 
>(n_threads)));
 
  302         auto partition_begin = partition_size * t;
 
  303         if (partition_begin >= nb_partitions) 
break;
 
  304         auto partition_end = std::min(partition_size * (t + 1), nb_partitions);
 
  305         auto hint_it = std::begin(partitions(t));
 
  306         for (
size_type i = partition_begin; i != partition_end; ++i){
 
  307           hint_it = partitions(t).insert(hint_it, i);
 
  309         current_partition(t) = partition_begin;
 
  313       for (
size_type t = 0; t != n_threads; ++t){
 
  314         partitions(t).insert(t);
 
  315         current_partition(t) = t;
 
  319     partitions_updated = 
true;
 
  322   #if defined _WIN32 && !defined (__GNUC__) 
  323     #define GETFEM_ON_WIN 
  326   parallel_boilerplate::
 
  327   parallel_boilerplate()
 
  328   : plocale{std::make_unique<standard_locale>()},
 
  329     pexception{std::make_unique<thread_exception>()} {
 
  331       _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
 
  335   void parallel_boilerplate::run_lambda(std::function<
void(
void)> lambda){
 
  336     pexception->run(lambda);
 
  339   parallel_boilerplate::~parallel_boilerplate(){
 
  341     _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
 
  343     pexception->rethrow();
 
  346   void parallel_execution(std::function<
void(
void)> lambda,
 
  347                           bool iterate_over_partitions){
 
  352     parallel_boilerplate boilerplate;
 
  353     auto &pm = partition_master::get();
 
  354     if (pm.get_nb_partitions() < true_thread_policy::num_threads()){
 
  355       pm.set_nb_partitions(true_thread_policy::num_threads());
 
  357     #pragma omp parallel default(shared) 
  359       if (iterate_over_partitions) {
 
  360         for (
auto &&partitions : partition_master::get()) {
 
  362           boilerplate.run_lambda(lambda);
 
  366         boilerplate.run_lambda(lambda);
 
  369     if (iterate_over_partitions) partition_master::get().rewind_partitions();
 
  373 #ifdef GETFEM_FORCE_SINGLE_THREAD_BLAS 
  375 # define BLAS_FORCE_SINGLE_THREAD                                       \ 
  376   int openblas_get_num_threads_res = 1;                                 \ 
  378     typedef int (* ptrfunc1)();                                         \ 
  379     ptrfunc1 func1 = ptrfunc1(dlsym(NULL, "openblas_get_num_threads")); \
 
  380     if (func1) openblas_get_num_threads_res = (*func1)();               \
 
  381     typedef void (* ptrfunc2)(int);                                     \
 
  382     ptrfunc2 func2 = ptrfunc2(dlsym(NULL, "openblas_set_num_threads")); \
 
  383     if (func2) (*func2)(1);                                             \
 
  385 # define BLAS_RESTORE_NUM_THREAD                                        \ 
  387     typedef void (* ptrfunc2)(int);                                     \ 
  388     ptrfunc func2 = ptrfunc2(dlsym(NULL, "openblas_set_num_threads"));  \
 
  389     if (func2) (*func)(openblas_get_num_threads_res);                   \
 
  392 # define BLAS_FORCE_SINGLE_THREAD 
  393 # define BLAS_RESTORE_NUM_THREAD 
  397   struct dummy_class_for_blas_nbthread_init {
 
  398     dummy_class_for_blas_nbthread_init(
void)
 
  399     { BLAS_FORCE_SINGLE_THREAD; }
 
  402   static dummy_class_for_blas_nbthread_init dcfbnti;
 
Iterator that runs over partitions on the current thread and sets the global (but thread-specific) pa...
 
A singleton that Manages partitions on individual threads.
 
partition_iterator begin()
beginning of the partitions for the current thread
 
size_type get_current_partition() const
active partition on the thread.
 
size_type get_nb_partitions() const
number of partitions or threads, depending on thread policy
 
partition_iterator end()
end of the partitions for the current thread
 
void set_nb_partitions(size_type)
for thread_behaviour::partition_threads set the total number of partitions.
 
void set_behaviour(thread_behaviour)
Sets the behaviour for the full program: either partitioning parallel loops according to the number o...
 
Allows to re-throw exceptions, generated in OpemMP parallel section.
 
A simple singleton implementation.
 
thread safe standard locale with RAII semantics
 
Tools for multithreaded, OpenMP and Boost based parallelization.
 
size_t size_type
used as the common size type in the library
 
GEneric Tool for Finite Element Methods.
 
bool not_multithreaded()
is the program is running on a single thread
 
size_type max_concurrency()
Maximum number of threads that can run concurrently.
 
bool me_is_multithreaded_now()
is the program running in the parallel section
 
void set_num_threads(int n)
set maximum number of OpenMP threads