Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2014-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : 23 : #include "OpenMP.h" 24 : #include "Tools.h" 25 : #include <cstdlib> 26 : #include <cstring> 27 : #if defined(_OPENMP) 28 : #include <omp.h> 29 : #endif 30 : #if defined(__linux__) && defined(_OPENMP) && defined(__PLUMED_HAS_DLOPEN) && defined(__PLUMED_HAS_DLADDR) 31 : #include <dlfcn.h> 32 : #endif 33 : 34 : namespace PLMD { 35 : 36 : namespace OpenMP { 37 : 38 807846 : void retainRuntime() { 39 : #if defined(__linux__) && defined(_OPENMP) && defined(__PLUMED_HAS_DLOPEN) && defined(__PLUMED_HAS_DLADDR) && defined(RTLD_NODELETE) 40 807846 : const char* retain=std::getenv("PLUMED_OPENMP_RETAIN_RUNTIME"); 41 807846 : if(retain && std::strcmp(retain, "no")==0) { 42 : return; 43 : } 44 : // A kernel can be unloaded while idle OpenMP workers are still executing in 45 : // the runtime. Retain that runtime, rather than the kernel or its other 46 : // dependencies. The function-local static also serializes concurrent callers. 47 6107 : static const bool retained=[] { 48 6107 : Dl_info runtime{}, kernel{}; 49 6107 : plumed_massert(dladdr(reinterpret_cast<void*>(&omp_get_thread_num), &runtime), 50 : "Cannot locate the OpenMP runtime"); 51 6107 : plumed_massert(dladdr(reinterpret_cast<void*>(&retainRuntime), &kernel), 52 : "Cannot locate the PLUMED kernel"); 53 : // With a statically linked OpenMP runtime, retaining this object would also 54 : // retain the whole kernel (or executable). Leave that case unchanged. 55 6107 : if(runtime.dli_fbase==kernel.dli_fbase) { 56 : return true; 57 : } 58 6107 : void* handle=dlopen(runtime.dli_fname, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); 59 6107 : plumed_massert(handle, "Cannot retain the OpenMP runtime"); 60 : // NODELETE persists after closing this extra reference. No per-load handle 61 : // is leaked, and normal dlclose() of individual kernels remains possible. 62 6107 : dlclose(handle); 63 6107 : return true; 64 807845 : }(); 65 : (void)retained; 66 : #endif 67 : } 68 : 69 : ///singleton struct to treat the openMP setting as a global variables, but with a layer of encapsulation 70 : struct OpenMPVars { 71 : unsigned cacheline_size=512; 72 : bool cache_set=false; 73 : unsigned num_threads=1; 74 : bool nt_env_set=false; 75 : static OpenMPVars & get() { 76 : static OpenMPVars vars; 77 : return vars; 78 : } 79 : private: 80 : OpenMPVars()=default; 81 : OpenMPVars(OpenMPVars&)=delete; 82 : OpenMPVars& operator=(OpenMPVars&&)=delete; 83 : }; 84 : 85 4 : void setNumThreads(const unsigned nt) { 86 4 : OpenMPVars::get().num_threads=nt; 87 4 : } 88 : 89 918685 : unsigned getCachelineSize() { 90 918685 : if(!OpenMPVars::get().cache_set) { 91 1037 : if(std::getenv("PLUMED_CACHELINE_SIZE")) { 92 1 : Tools::convert(std::getenv("PLUMED_CACHELINE_SIZE"),OpenMPVars::get().cacheline_size); 93 : } 94 1037 : OpenMPVars::get().cache_set = true; 95 : } 96 918685 : return OpenMPVars::get().cacheline_size; 97 : } 98 : 99 45767925 : unsigned getNumThreads() { 100 45767925 : if(!OpenMPVars::get().nt_env_set) { 101 1039 : if(std::getenv("PLUMED_NUM_THREADS")) { 102 1039 : Tools::convert(std::getenv("PLUMED_NUM_THREADS"),OpenMPVars::get().num_threads); 103 : } 104 1039 : OpenMPVars::get().nt_env_set = true; 105 : } 106 45767925 : return OpenMPVars::get().num_threads; 107 : } 108 : 109 76360763 : unsigned getThreadNum() { 110 : #if defined(_OPENMP) 111 76360763 : return omp_get_thread_num(); 112 : #else 113 : return 0; 114 : #endif 115 : } 116 : 117 : }//namespace OpenMP 118 : }//namespace PLMD