LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
threads.cc
Go to the documentation of this file.
1 #include <cstddef>
2 #include <cstdlib>
3 
4 #include <iostream>
5 
6 #include "lsst/base/library.h"
7 #include "lsst/base/threads.h"
8 
9 namespace lsst {
10 namespace base {
11 
12 namespace {
13 
14 typedef int (Getter)(void);
15 typedef void (Setter)(int);
16 
17 Getter* getOpenBlasThreads = NULL;
18 Setter* setOpenBlasThreads = NULL;
19 Getter* getMklThreads = NULL;
20 Setter* setMklThreads = NULL;
21 
22 bool loadOpenBlas() {
23  if (haveOpenBlas) {
24  return true;
25  }
26 
27  try {
28  getOpenBlasThreads = loadSymbol<Getter>("libopenblas", "goto_get_num_procs");
29  // Believe it or not, the function which returns the number of threads
30  // that OpenBLAS will actually use is called "goto_get_num_procs". The
31  // number returned by THIS function, and not "openblas_get_num_threads"
32  // nor "openblas_get_num_procs", is modified by calls to
33  // "openblas_set_num_threads". Confused? Me too.
34  setOpenBlasThreads = loadSymbol<Setter>("libopenblas", "openblas_set_num_threads");
35  } catch (LibraryException const&) {
36  return false;
37  }
38  return true;
39 }
40 
41 bool loadMkl() {
42  if (haveMkl) {
43  return true;
44  }
45 
46  if (!canLoadLibrary("libmkl_core")) {
47  return false;
48  }
49 
50  // We will set the number of threads through OMP because that's easier.
51  // (There are multiple mkl libraries, and each has a function to set the number of threads.)
52  try {
53  getMklThreads = loadSymbol<Getter>("libiomp5", "omp_get_max_threads");
54  setMklThreads = loadSymbol<Setter>("libiomp5", "omp_set_num_threads");
55  } catch (LibraryException const&) {
56  return false;
57  }
58  return true;
59 }
60 
61 bool disableImplicitThreadingImpl(
62  std::string const& package, // Name of package
63  std::initializer_list<std::string const> envvars, // Environment variables to check
64  Getter* getter, // Function to get number of threads
65  Setter* setter // Function to set number of threads
66  )
67 {
68  for (auto&& ss : envvars) {
69  if (std::getenv(ss.c_str())) {
70  return false; // User is being explicit
71  }
72  }
73  unsigned int numThreads = getter();
74  if (numThreads <= 1) {
75  return false;
76  }
77 
78  std::cerr << "WARNING: You are using " << package << " with multiple threads (" << numThreads <<
79  "), but have not\n" <<
80  "specified the number of threads using one of the " << package <<
81  " environment variables:\n";
82 
83  // Join list of environment variables. An alternative is
84  // boost::algorithm::join(envvars, ", ")
85  // but we are trying to control the proliferation of Boost usage.
86  std::cerr << *envvars.begin();
87  for (auto iter = envvars.begin() + 1; iter != envvars.end(); ++iter) {
88  std::cerr << ", " << *iter;
89  }
90 
91  std::cerr << ".\n" <<
92  "This may indicate that you are unintentionally using multiple threads, which may\n"
93  "cause problems. WE HAVE THEREFORE DISABLED " << package << " THREADING. If you know\n" <<
94  "what you are doing and want threads enabled implicitly, set the environment\n" <<
95  "variable " << allowEnvvar << ".\n";
96  setter(1);
97  return true;
98 }
99 
100 
101 } // anonymous namespace
102 
103 
104 extern bool const haveOpenBlas = loadOpenBlas();
105 extern bool const haveMkl = loadMkl();
106 
107 void setNumThreads(unsigned int numThreads)
108 {
109  if (!haveOpenBlas && !haveMkl && numThreads != 0 && numThreads != 1) {
110  throw NoThreadsException();
111  }
112  if (haveOpenBlas) {
113  setOpenBlasThreads(numThreads);
114  }
115  if (haveMkl) {
116  setMklThreads(numThreads);
117  }
118 }
119 
120 unsigned int getNumThreads()
121 {
122  unsigned int numThreads = 0;
123  if (haveOpenBlas) {
124  numThreads = std::max(numThreads, static_cast<unsigned int>(getOpenBlasThreads()));
125  }
126  if (haveMkl) {
127  numThreads = std::max(numThreads, static_cast<unsigned int>(getMklThreads()));
128  }
129  return numThreads;
130 }
131 
133 {
134  if (std::getenv(allowEnvvar.c_str())) {
135  return false; // The user knows what he's doing; no intervention performed
136  }
137 
138  bool intervened = false; // Did we intervene on behalf of the user?
139  if (haveOpenBlas) {
140  intervened |= disableImplicitThreadingImpl(
141  "OpenBLAS",
142  {"OPENBLAS_NUM_THREADS", "GOTO_NUM_THREADS", "OMP_NUM_THREADS"},
143  getOpenBlasThreads,
144  setOpenBlasThreads
145  );
146  }
147  if (haveMkl) {
148  intervened |= disableImplicitThreadingImpl(
149  "MKL",
150  {"MKL_NUM_THREADS", "MKL_DOMAIN_NUM_THREADS", "OMP_NUM_THREADS"},
151  getMklThreads,
152  setMklThreads
153  );
154  }
155  return intervened;
156 }
157 
158 }} // namespace lsst::base
bool disableImplicitThreading()
Disable threading that has not been set explicitly.
Definition: threads.cc:132
bool const haveMkl
Is MKL available?
Definition: threads.cc:105
STL class.
T getenv(T... args)
No threading library is available.
Definition: threads.h:20
A base class for image defects.
std::string const allowEnvvar
Environment variable to allow implicit threading.
Definition: threads.h:16
T max(T... args)
void setNumThreads(unsigned int numThreads)
Set number of threads to use.
Definition: threads.cc:107
Definition: __init__.py:1
unsigned int getNumThreads()
Get maximum number of threads we might use.
Definition: threads.cc:120
T c_str(T... args)
bool canLoadLibrary(std::string const &libName)
Return whether we can load a library.
Definition: library.cc:37
bool const haveOpenBlas
Is OpenBLAS available?
Definition: threads.cc:104