Reference documentation for deal.II version 9.2.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
multithread_info.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2020 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
17 #include <deal.II/base/utilities.h>
18 
19 #ifdef DEAL_II_HAVE_UNISTD_H
20 # include <unistd.h>
21 #endif
22 
23 #if (defined(__MACH__) && defined(__APPLE__)) || defined(__FreeBSD__)
24 # include <sys/sysctl.h>
25 # include <sys/types.h>
26 #endif
27 
28 #include <algorithm>
29 
30 #ifdef DEAL_II_WITH_THREADS
31 # define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
32 # include <tbb/task_scheduler_init.h>
33 # undef TBB_SUPPRESS_DEPRECATED_MESSAGES
34 #endif
35 
37 
38 #ifdef DEAL_II_WITH_THREADS
39 
40 /* Detecting how many processors a given machine has is something that
41  varies greatly between operating systems. For a few operating
42  systems, we have figured out how to do that below, but some others
43  are still missing. If you find a way to do this on your favorite
44  system, please let us know.
45  */
46 
47 
48 # if defined(__linux__) || defined(__sun__) || defined(__osf__) || \
49  defined(_AIX)
50 
51 unsigned int
53 {
54  return sysconf(_SC_NPROCESSORS_ONLN);
55 }
56 
57 # elif (defined(__MACH__) && defined(__APPLE__)) || defined(__FreeBSD__)
58 // This is only tested on a dual G5 2.5GHz running MacOSX 10.3.6
59 // and on an Intel Mac Book Pro.
60 // If it doesn't work please contact the mailinglist.
61 unsigned int
63 {
64  int mib[2];
65  int n_cpus;
66  std::size_t len;
67 
68  mib[0] = CTL_HW;
69  mib[1] = HW_NCPU;
70  len = sizeof(n_cpus);
71  sysctl(mib, 2, &n_cpus, &len, nullptr, 0);
72 
73  return n_cpus;
74 }
75 
76 # else
77 
78 // If you get n_cpus=1 although you are on a multi-processor machine,
79 // then this may have two reasons: either because the system macros,
80 // e.g.__linux__, __sgi__, etc. weren't defined by the compiler or the
81 // detection of processors is really not implemented for your specific
82 // system. In the first case you can add e.g. -D__sgi__ to your
83 // compiling flags, in the latter case you need to implement the
84 // get_n_cpus() function for your system.
85 //
86 // In both cases, this #else case is compiled, a fact that you can
87 // easily verify by uncommenting the following #error directive,
88 // recompiling and getting a compilation error right at that line.
89 // After definition of the system macro or the implementation of the
90 // new detection this #error message during compilation shouldn't
91 // occur any more.
92 //
93 // Please send all new implementations of detection of processors to
94 // the deal.II mailing list, such that it can be included into the
95 // next deal.II release.
96 
97 //#error Detection of Processors not supported on this OS. Setting n_cpus=1 by
98 // default.
99 
100 unsigned int
102 {
103  return 1;
104 }
105 
106 # endif
107 
108 unsigned int
110 {
112 }
113 
114 
115 void
116 MultithreadInfo::set_thread_limit(const unsigned int max_threads)
117 {
118  // set the maximal number of threads to the given value as specified
119  n_max_threads = max_threads;
120 
121  // then also see if something was given in the environment
122  {
123  const char *penv = getenv("DEAL_II_NUM_THREADS");
124  if (penv != nullptr)
125  {
126  unsigned int max_threads_env = numbers::invalid_unsigned_int;
127  try
128  {
129  max_threads_env = Utilities::string_to_int(std::string(penv));
130  }
131  catch (...)
132  {
133  AssertThrow(
134  false,
135  ExcMessage(
136  std::string(
137  "When specifying the <DEAL_II_NUM_THREADS> environment "
138  "variable, it needs to be something that can be interpreted "
139  "as an integer. The text you have in the environment "
140  "variable is <") +
141  penv + ">"));
142  }
143 
144  AssertThrow(max_threads_env > 0,
145  ExcMessage(
146  "When specifying the <DEAL_II_NUM_THREADS> environment "
147  "variable, it needs to be a positive number."));
148 
150  n_max_threads = std::min(n_max_threads, max_threads_env);
151  else
152  n_max_threads = max_threads_env;
153  }
154  }
155  // Without restrictions from the user query TBB for the recommended number
156  // of threads:
158  n_max_threads = tbb::task_scheduler_init::default_num_threads();
159 
160  // Initialize the scheduler and destroy the old one before doing so
161  static tbb::task_scheduler_init dummy(tbb::task_scheduler_init::deferred);
162  if (dummy.is_active())
163  dummy.terminate();
164  dummy.initialize(n_max_threads);
165 }
166 
167 
168 unsigned int
170 {
172  return n_max_threads;
173 }
174 
175 
176 #else // not in MT mode
177 
178 unsigned int
180 {
181  return 1;
182 }
183 
184 unsigned int
186 {
187  return 1;
188 }
189 
190 unsigned int
192 {
193  return 1;
194 }
195 
196 void
197 MultithreadInfo::set_thread_limit(const unsigned int)
198 {}
199 
200 #endif
201 
202 
203 bool
205 {
206  return n_threads() == 1;
207 }
208 
209 
210 std::size_t
212 {
213  // only simple data elements, so
214  // use sizeof operator
215  return sizeof(MultithreadInfo);
216 }
217 
218 
219 void
221 {
222  static bool done = false;
223  if (done)
224  return;
225 
227  done = true;
228 }
229 
230 
231 
234 
235 namespace
236 {
237  // Force the first call to set_thread_limit happen before any tasks in TBB are
238  // used. This is necessary as tbb::task_scheduler_init has no effect if TBB
239  // got automatically initialized (which happens the first time we use it).
240  struct DoOnce
241  {
242  DoOnce()
243  {
245  }
246  } do_once;
247 } // namespace
248 
static const unsigned int invalid_unsigned_int
Definition: types.h:191
static const unsigned int n_cpus
MultithreadInfo()=delete
static unsigned int n_cores()
#define AssertThrow(cond, exc)
Definition: exceptions.h:1531
static ::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1419
static void initialize_multithreading()
static bool is_running_single_threaded()
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:359
const types::global_dof_index * dummy()
Definition: dof_handler.cc:59
static unsigned int n_max_threads
static std::size_t memory_consumption()
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:358
T min(const T &t, const MPI_Comm &mpi_communicator)
static void set_thread_limit(const unsigned int max_threads=numbers::invalid_unsigned_int)
int string_to_int(const std::string &s)
Definition: utilities.cc:609
static unsigned int n_threads()
static ::ExceptionBase & ExcInternalError()
static unsigned int get_n_cpus()