LSST Applications g0da5cf3356+25b44625d0,g17e5ecfddb+50a5ac4092,g1c76d35bf8+585f0f68a2,g295839609d+8ef6456700,g2e2c1a68ba+cc1f6f037e,g38293774b4+62d12e78cb,g3b44f30a73+2891c76795,g48ccf36440+885b902d19,g4b2f1765b6+0c565e8f25,g5320a0a9f6+bd4bf1dc76,g56364267ca+403c24672b,g56b687f8c9+585f0f68a2,g5c4744a4d9+78cd207961,g5ffd174ac0+bd4bf1dc76,g6075d09f38+3075de592a,g667d525e37+cacede5508,g6f3e93b5a3+da81c812ee,g71f27ac40c+cacede5508,g7212e027e3+eb621d73aa,g774830318a+18d2b9fa6c,g7985c39107+62d12e78cb,g79ca90bc5c+fa2cc03294,g881bdbfe6c+cacede5508,g91fc1fa0cf+82a115f028,g961520b1fb+2534687f64,g96f01af41f+f2060f23b6,g9ca82378b8+cacede5508,g9d27549199+78cd207961,gb065e2a02a+ad48cbcda4,gb1df4690d6+585f0f68a2,gb35d6563ee+62d12e78cb,gbc3249ced9+bd4bf1dc76,gbec6a3398f+bd4bf1dc76,gd01420fc67+bd4bf1dc76,gd59336e7c4+c7bb92e648,gf46e8334de+81c9a61069,gfed783d017+bd4bf1dc76,v25.0.1.rc3
LSST Data Management Base Package
Loading...
Searching...
No Matches
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
9namespace lsst {
10namespace base {
11
12namespace {
13
14typedef int (Getter)(void);
15typedef void (Setter)(int);
16
17Getter* getOpenBlasThreads = NULL;
18Setter* setOpenBlasThreads = NULL;
19Getter* getMklThreads = NULL;
20Setter* setMklThreads = NULL;
21
22bool 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
41bool 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
61bool 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
104extern bool const haveOpenBlas = loadOpenBlas();
105extern bool const haveMkl = loadMkl();
106
107void 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
120unsigned 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{
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