LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
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
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
A base class for image defects.