LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
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