LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
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
T c_str(T... args)
No threading library is available.
Definition: threads.h:20
T getenv(T... args)
T max(T... args)
unsigned int getNumThreads()
Get maximum number of threads we might use.
Definition: threads.cc:120
bool canLoadLibrary(std::string const &libName)
Return whether we can load a library.
Definition: library.cc:37
bool disableImplicitThreading()
Disable threading that has not been set explicitly.
Definition: threads.cc:132
bool const haveOpenBlas
Is OpenBLAS available?
Definition: threads.cc:104
std::string const allowEnvvar
Environment variable to allow implicit threading.
Definition: threads.h:16
bool const haveMkl
Is MKL available?
Definition: threads.cc:105
void setNumThreads(unsigned int numThreads)
Set number of threads to use.
Definition: threads.cc:107
A base class for image defects.