Reference documentation for deal.II version 9.4.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 - 2022 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
18
19#include <algorithm>
20#include <cstdlib> // for std::getenv
21#include <mutex>
22#include <thread>
23
24#ifdef DEAL_II_WITH_TBB
25# ifdef DEAL_II_TBB_WITH_ONEAPI
26# include <tbb/global_control.h>
27# else
28# include <tbb/task_scheduler_init.h>
29# endif
30#endif
31
32
33#ifdef DEAL_II_WITH_TASKFLOW
35# include <taskflow/taskflow.hpp>
37#endif
38
40
41
42unsigned int
44{
45 // There is a slight semantic change between our n_cores() call and the
46 // std::thread alternative: in case of an error the latter one returns 0
47 // in contrast to a 1 that n_cores() used to do. For compatibility, let's
48 // translate to our numbering scheme:
49 const unsigned int n_cores = std::thread::hardware_concurrency();
50 return n_cores == 0 ? 1 : n_cores;
51}
52
53
54void
55MultithreadInfo::set_thread_limit(const unsigned int max_threads)
56{
57 // set the maximal number of threads to the given value as specified
58 n_max_threads = max_threads;
59
60 // then also see if something was given in the environment
61 {
62 if (const char *penv = std::getenv("DEAL_II_NUM_THREADS"))
63 {
64 unsigned int max_threads_env = numbers::invalid_unsigned_int;
65 try
66 {
67 max_threads_env = Utilities::string_to_int(std::string(penv));
68 }
69 catch (...)
70 {
72 false,
74 std::string(
75 "When specifying the <DEAL_II_NUM_THREADS> environment "
76 "variable, it needs to be something that can be interpreted "
77 "as an integer. The text you have in the environment "
78 "variable is <") +
79 penv + ">"));
80 }
81
82 AssertThrow(max_threads_env > 0,
84 "When specifying the <DEAL_II_NUM_THREADS> environment "
85 "variable, it needs to be a positive number."));
86
88 n_max_threads = std::min(n_max_threads, max_threads_env);
89 else
90 n_max_threads = max_threads_env;
91 }
92 }
93
94 // If we have not set the number of allowed threads yet, just default to
95 // the number of available cores
98
99#ifdef DEAL_II_WITH_TBB
100# ifdef DEAL_II_TBB_WITH_ONEAPI
101 // tbb::global_control is a class that affects the specified behavior of
102 // tbb during its lifetime. Thus, in order to set a global thread limit
103 // for tbb we have to maintain the object throughout the execution of the
104 // program. We do this by maintaining a static std::unique_ptr.
105 //
106 // A std::unique_ptr is a good choice here because tbb::global_control
107 // does not provide a mechanism to override its setting - we can only
108 // delete the old and replace it with a new one.
109 static std::unique_ptr<tbb::global_control> tbb_global_control;
110 tbb_global_control = std::make_unique<tbb::global_control>(
111 tbb::global_control::max_allowed_parallelism, n_max_threads);
112
113# else
114 // Initialize the scheduler and destroy the old one before doing so
115 static tbb::task_scheduler_init dummy(tbb::task_scheduler_init::deferred);
116 if (dummy.is_active())
117 dummy.terminate();
118 dummy.initialize(n_max_threads);
119# endif
120#endif
121
122#ifdef DEAL_II_WITH_TASKFLOW
123 executor = std::make_unique<tf::Executor>(n_max_threads);
124#endif
125}
126
127
128
129unsigned int
131{
133 return n_max_threads;
134}
135
136
137
138bool
140{
141 return n_threads() == 1;
142}
143
144
145
146std::size_t
148{
149 // only simple data elements, so use sizeof operator
150 return sizeof(MultithreadInfo);
151}
152
153
154
155void
157{
158 static std::once_flag is_initialized;
159 std::call_once(is_initialized, []() {
161 });
162}
163
164
165
166#ifdef DEAL_II_WITH_TASKFLOW
167tf::Executor &
169{
170 // This should not trigger in normal user code, because we initialize the
171 // Executor in the static DoOnce struct at the end of this file unless you
172 // ask for the Executor before this static object gets constructed.
173 Assert(
174 executor.get() != nullptr,
176 "Please initialize multithreading using MultithreadInfo::set_thread_limit() first."));
177 return *(executor.get());
178}
179
180std::unique_ptr<tf::Executor> MultithreadInfo::executor = nullptr;
181#endif
182
184
185namespace
186{
187 // Force the first call to set_thread_limit happen before any tasks in TBB are
188 // used. This is necessary as tbb::task_scheduler_init has no effect if TBB
189 // got automatically initialized (which happens the first time we use it).
190 struct DoOnce
191 {
192 DoOnce()
193 {
195 }
196 } do_once;
197} // namespace
198
static unsigned int n_max_threads
MultithreadInfo()=delete
static bool is_running_single_threaded()
static std::unique_ptr< tf::Executor > executor
static void initialize_multithreading()
static unsigned int n_cores()
static unsigned int n_threads()
static void set_thread_limit(const unsigned int max_threads=numbers::invalid_unsigned_int)
static std::size_t memory_consumption()
static tf::Executor & get_taskflow_executor()
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:442
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
Definition: config.h:456
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:443
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
Definition: config.h:495
#define Assert(cond, exc)
Definition: exceptions.h:1473
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1583
int string_to_int(const std::string &s)
Definition: utilities.cc:608
static const unsigned int invalid_unsigned_int
Definition: types.h:201
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)