Reference documentation for deal.II version Git 7026f387cc 2019-10-15 14:19:01 -0400
\(\newcommand{\dealcoloneq}{\mathrel{\vcenter{:}}=}\)
multithread_info.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2019 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 
16 #include <deal.II/base/multithread_info.h>
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 # include <tbb/task_scheduler_init.h>
32 #endif
33 
34 DEAL_II_NAMESPACE_OPEN
35 
36 #ifdef DEAL_II_WITH_THREADS
37 
38 /* Detecting how many processors a given machine has is something that
39  varies greatly between operating systems. For a few operating
40  systems, we have figured out how to do that below, but some others
41  are still missing. If you find a way to do this on your favorite
42  system, please let us know.
43  */
44 
45 
46 # if defined(__linux__) || defined(__sun__) || defined(__osf__) || \
47  defined(_AIX)
48 
49 unsigned int
51 {
52  return sysconf(_SC_NPROCESSORS_ONLN);
53 }
54 
55 # elif (defined(__MACH__) && defined(__APPLE__)) || defined(__FreeBSD__)
56 // This is only tested on a dual G5 2.5GHz running MacOSX 10.3.6
57 // and on an Intel Mac Book Pro.
58 // If it doesn't work please contact the mailinglist.
59 unsigned int
61 {
62  int mib[2];
63  int n_cpus;
64  std::size_t len;
65 
66  mib[0] = CTL_HW;
67  mib[1] = HW_NCPU;
68  len = sizeof(n_cpus);
69  sysctl(mib, 2, &n_cpus, &len, nullptr, 0);
70 
71  return n_cpus;
72 }
73 
74 # else
75 
76 // If you get n_cpus=1 although you are on a multi-processor machine,
77 // then this may have two reasons: either because the system macros,
78 // e.g.__linux__, __sgi__, etc. weren't defined by the compiler or the
79 // detection of processors is really not implemented for your specific
80 // system. In the first case you can add e.g. -D__sgi__ to your
81 // compiling flags, in the latter case you need to implement the
82 // get_n_cpus() function for your system.
83 //
84 // In both cases, this #else case is compiled, a fact that you can
85 // easily verify by uncommenting the following #error directive,
86 // recompiling and getting a compilation error right at that line.
87 // After definition of the system macro or the implementation of the
88 // new detection this #error message during compilation shouldn't
89 // occur any more.
90 //
91 // Please send all new implementations of detection of processors to
92 // the deal.II mailing list, such that it can be included into the
93 // next deal.II release.
94 
95 //#error Detection of Processors not supported on this OS. Setting n_cpus=1 by
96 // default.
97 
98 unsigned int
100 {
101  return 1;
102 }
103 
104 # endif
105 
106 unsigned int
108 {
110 }
111 
112 
113 void
114 MultithreadInfo::set_thread_limit(const unsigned int max_threads)
115 {
116  // set the maximal number of threads to the given value as specified
117  n_max_threads = max_threads;
118 
119  // then also see if something was given in the environment
120  {
121  const char *penv = getenv("DEAL_II_NUM_THREADS");
122  if (penv != nullptr)
123  {
124  unsigned int max_threads_env = numbers::invalid_unsigned_int;
125  try
126  {
127  max_threads_env = Utilities::string_to_int(std::string(penv));
128  }
129  catch (...)
130  {
131  AssertThrow(
132  false,
133  ExcMessage(
134  std::string(
135  "When specifying the <DEAL_II_NUM_THREADS> environment "
136  "variable, it needs to be something that can be interpreted "
137  "as an integer. The text you have in the environment "
138  "variable is <") +
139  penv + ">"));
140  }
141 
142  AssertThrow(max_threads_env > 0,
143  ExcMessage(
144  "When specifying the <DEAL_II_NUM_THREADS> environment "
145  "variable, it needs to be a positive number."));
146 
148  n_max_threads = std::min(n_max_threads, max_threads_env);
149  else
150  n_max_threads = max_threads_env;
151  }
152  }
153  // Without restrictions from the user query TBB for the recommended number
154  // of threads:
156  n_max_threads = tbb::task_scheduler_init::default_num_threads();
157 
158  // Initialize the scheduler and destroy the old one before doing so
159  static tbb::task_scheduler_init dummy(tbb::task_scheduler_init::deferred);
160  if (dummy.is_active())
161  dummy.terminate();
162  dummy.initialize(n_max_threads);
163 }
164 
165 
166 unsigned int
168 {
170  return n_max_threads;
171 }
172 
173 
174 #else // not in MT mode
175 
176 unsigned int
178 {
179  return 1;
180 }
181 
182 unsigned int
184 {
185  return 1;
186 }
187 
188 unsigned int
190 {
191  return 1;
192 }
193 
194 void
195 MultithreadInfo::set_thread_limit(const unsigned int)
196 {}
197 
198 #endif
199 
200 
201 bool
203 {
204  return n_threads() == 1;
205 }
206 
207 
208 std::size_t
210 {
211  // only simple data elements, so
212  // use sizeof operator
213  return sizeof(MultithreadInfo);
214 }
215 
216 
217 void
219 {
220  static bool done = false;
221  if (done)
222  return;
223 
225  done = true;
226 }
227 
228 
229 
232 
233 namespace
234 {
235  // Force the first call to set_thread_limit happen before any tasks in TBB are
236  // used. This is necessary as tbb::task_scheduler_init has no effect if TBB
237  // got automatically initialized (which happens the first time we use it).
238  struct DoOnce
239  {
240  DoOnce()
241  {
243  }
244  } do_once;
245 } // namespace
246 
247 DEAL_II_NAMESPACE_CLOSE
static const unsigned int invalid_unsigned_int
Definition: types.h:187
static const unsigned int n_cpus
MultithreadInfo()=delete
static unsigned int n_cores()
#define AssertThrow(cond, exc)
Definition: exceptions.h:1519
static ::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1407
static void initialize_multithreading()
static bool is_running_single_threaded()
static unsigned int n_max_threads
static std::size_t memory_consumption()
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:488
static unsigned int n_threads()
static ::ExceptionBase & ExcInternalError()
static unsigned int get_n_cpus()